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