洛谷P1111 修复公路

关于本题目

由于题目原本不是树,而是图,而题目又问的是最短修好路得时间,如果是图,那么会有多条路联通两个节点,而其中必定有一条最短时间修好的路,那么最终必定是其中的包含的最小树,所以我们要生成最小树。

最小生成树之Kruskal算法

这个算法用到的方法是,先将所有边按照权重(此处是时间长短)排序,我是从小到大排序的。排序用到的算法复杂度只能是O(nlgn)O(nlgn)以下的,不然会超时。比如快速排序,这些必须学,此处不做赘述。排好序以后,就从权重最小的边开始,因为此时所有节点的祖先值都为自己(也就是所有的节点都是独立的),运用并查集进行查的操作,看一下边的左右节点的祖先是否相同,如果最老祖先相同,就代表这两个节点已经在一个树里面了,你再去连这两个节点,就会练成图,所以最老祖先相同则不连,如果有不同的最老祖先,那么就对这两个节点进行

并的操作,这样还是树。直到最后,这个算法完毕后,最小树就生成了。最小生成树具体算法如下:

// ]]>
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <string>
 4 #include <algorithm>
 5 #include <cstring>
 6 #define maxn 300000
 7 
 8 using namespace std;
 9 
10 int f[maxn];
11 
12 struct node {
13     int x, y, t;
14 }e[maxn];
15 
16 int rf(int a)
17 {
18     if (f[a])
19     {
20         f[a] = rf(f[a]);
21         return f[a];
22     }
23     else return a;
24 }
25 
26 int cmp(node a, node b)
27 {
28     return a.t<b.t;
29 }
30 
31 int merge(int x)
32 {
33         if (x != f[x]) return f[x] = merge(f[x]);
34         return f[x];
35 }
36 
37 
38 int main()
39 {
40     int N, M;
41     cin >> N >> M;
42     for (int i = 1; i <= N; i++)
43     {
44         f[i] = i;
45     }
46     for (int i = 1; i <= M; i++)
47     {
48         cin >> e[i].x >> e[i].y >> e[i].t;
49     }
50     sort(e + 1, e + 1 + M, cmp);
51     int num = 0, tot = 0;
52     for (int i = 1; i <= M; i++)
53     {
54         int u = merge(e[i].x), v = merge(e[i].y);
55         if (u != v)
56         {
57             f[u] = v;
58             num++;
59             tot = max(tot, e[i].t);
60         }
61     }
62     if (num >= N - 1) cout << tot << endl;
63     else cout << -1 << endl;
64     return 0;
65 }

更多代码请进入:https://github.com/tomatoschool     

猜你喜欢

转载自www.cnblogs.com/zxfzxf/p/9558617.html
今日推荐