Catalog
  1. 1. 解题思路
  2. 2. 具体做法
    1. 2.1. 核心算法
    2. 2.2. 注意事项
  3. 3. 代码
滑雪-题解

查看原题请戳这里

解题思路

首先,因为题目要求求“即满足经过景点数最大的前提下使得滑行总距离最小”,所以这道题目我们可以用最小生成树来解决。

具体做法

核心算法

这里推荐用kruskal去求最小生成树(prim虽然加上堆优化也应该不会超时,但是ta真的是代码难敲效率还低qwq)。
因为这道题目对于每个点的高度都有一个限制,所以有些点即使是有边相连也是到不了的。此时我们可以先统计可以到达的边,然后只储存两个端点都可以到达的边。

注意事项

因为每个点具有高度,所以建边是应根据情况选择建单向边还是双向边。
由于每个点的高度都有限制,所以并不是某个点在一开始统计的时候统计为能到达就可以随意选边。

如图,如果我们直接按照边权从小到大排序,那么我们会选择(2)号边。但实际上,3号点是到不了4号点的,所以我们应优先选择终点高度高的(1)号边。 因此我们在对边进行排序是,应把终点的高度设为第一关键字,把边权设为第二关键字

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
#define INF 0x7fffffff
#define re register

using namespace std;

int read()
{
register int x = 0,f = 1;register char ch;
ch = getchar();
while(ch > '9' || ch < '0'){if(ch == '-') f = -f;ch = getchar();}
while(ch <= '9' && ch >= '0'){x = x * 10 + ch - 48;ch = getchar();}
return x * f;
}

struct edge1{
int next,to,k,from;
}edge[2000005];

struct edge2{
int x,y,k;
}e[2000005];

long long n,m,u,v,k,t,cnt,ans,tot,h[100005],d[100005],vis[100005],fa[100005];

void add(int x, int y, int k)
{
edge[++cnt].to = y;
edge[cnt].k = k;
edge[cnt].next = d[x];
edge[cnt].from = x;
d[x] = cnt;
}

void dfs(int s)
{
vis[s] = 1;
for(re int i = d[s]; i; i = edge[i].next) if(!vis[edge[i].to]) dfs(edge[i].to);
}

int mysort(edge2 a, edge2 b)
{
if(h[a.y] != h[b.y]) return h[a.y] > h[b.y];
return a.k < b.k;
}

int find(int x) {if(fa[x] == x) return x; return fa[x] = find(fa[x]);}

void kruskal()
{
for(re int i = 1; i <= n; i++) fa[i] = i;
sort(e + 1, e + t + 1, mysort);
for(re int i = 1; i <= t; i++)
{
if(find(e[i].x) != find(e[i].y))
{
ans = ans + e[i].k;
fa[find(e[i].x)] = find(e[i].y);
}
}
}

int main()
{
n = read(); m = read();
for(re int i = 1; i <= n; i++) h[i] = read();
for(re int i = 1; i <= m; i++)
{
u = read(); v = read(); k = read();
if(h[u] >= h[v]) add(u,v,k);
if(h[u] <= h[v]) add(v,u,k);
}
dfs(1);
for(re int i = 1; i <= cnt; i ++)
{
if((edge[i].from != edge[i - 1].to || edge[i].to != edge[i - 1].from) && vis[edge[i].from] && vis[edge[i].to])
{
e[++t].k = edge[i].k;
e[t].x = edge[i].from;
e[t].y = edge[i].to;
}
}
kruskal();
for(re int i = 1; i <= n; i++) if(vis[i]) tot ++;
printf("%lld %lld\n", tot, ans);
return 0;
}
Author: wflight
Link: http://yoursite.com/2019/08/02/滑雪-题解/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
  • 支付寶

Comment