CCF-CSP 201812-4 数据中心(Kruskal最小生成树)
作者:互联网
Kruskal最小生成树
代码注释中粗略地分析了思路。因为解中根节点与其它所有节点必须连通,因此解一定是生成树。由注释中的分析可知,最优解一定是最小生成树。
Kruskal算法其实是一种贪心算法,每次都选取权值小的边去构造生成树,使得最终的生成树边权总和最小。若新加入的边不会使图中连通的点增加,则该边应当丢弃,这就需要判断边两端的顶点是否在同一连通分量中——通过并查集实现。根据生成树性质,当恰有N-1条边加入到生成树中时,说明构造完毕。(N为顶点个数)
传输时间为何是路径上的最大时间?可以参考流水线实现,即各个节点的收发是异步的,对于一个节点,并不是待所有数据都接收完毕后,再将收到的数据发送出去。这类似于双端口缓存,写端口(接收端送来数据)和读端口(传输至发送端)以不同的速率写入和读出数据。
PS:解题时遇到一个罕见的问题:若在程序中定义标识符rank,则CSP报编译错误。改为rank_1等标识符后通过。
这可能是由于判题系统占用了rank这个标识符,导致编译时出现重定义错误。
AC代码:
1 /* 2 * 1. 若定义变量名rank,则CSP报编译出错,改为rank_1后通过。原因未知! 3 * 4 * 2. 题中“树结构的传输时间”实质上为连通路径上最大的传输时间。目标是求使总传输时间最小的树: 5 * 当连通路径上传输时间总和最小时,其中的最大传输时间也最小(传输时间不为负值)。 6 * 因此所求“最优结构”是原图的最小生成树。 7 * 3. 使用kruskal算法时,基于题目所给出的数据规模,应对并查集采用简单的按秩合并优化或者路径压缩。 8 * 秩增加的唯一条件是:两个集合对应子树的秩相等。因为合并集合时, 9 * 总是将秩小的树合并到秩大的树上,总秩不会发生任何改变,除非两树等秩时,才使总秩增加1。 10 * 本例实测,单纯使用简单按秩合并优化后,执行时间为原来的 1/40! 11 * 4. 还可考虑路径压缩算法,即每次father()搜索时,将被查找过的节点的parent都指向它们的直接根节点。 12 * 递归实现:Line 45。 13 * 本例实测,单纯使用路径压缩优化后,执行时间为原来的 1/40! 14 */ 15 16 #include <iostream> 17 #include <algorithm> 18 19 #include <fstream> 20 21 struct Edge { 22 int u, v; 23 int t; 24 25 inline bool operator < (const Edge &e) const { 26 return t < e.t; 27 } 28 inline bool operator ==(const Edge &e) const { 29 return u==e.u || v==e.v; 30 } 31 }; 32 33 using namespace std; 34 35 static int *parent; 36 static int *rank_1; 37 38 static int father(int p) { 39 #if 0 // not optimized 40 while (parent[p] != p) { 41 p = parent[p]; 42 } 43 return p; 44 #else 45 return (parent[p] == p) ? p : (parent[p] = father(parent[p])); 46 #endif 47 } 48 49 int main(void) { 50 ios::sync_with_stdio(false); 51 52 /*#if 0 53 ifstream fin("input.txt"); 54 cin.rdbuf(fin.rdbuf()); 55 #endif*/ 56 57 int n, m, root; 58 cin >> n >> m >> root; 59 60 Edge *e = new Edge[m]; 61 parent = new int[n+1]; 62 rank_1 = new int[n+1]; 63 64 for(int i=0; i<m; ++i) { 65 cin >> e[i].v >> e[i].u >> e[i].t; 66 } 67 for(int i=1; i<=n; ++i) { 68 parent[i] = i; 69 rank_1[i] = 1; 70 } 71 72 sort(e, e+m); 73 74 int k = 0; 75 int ans = 0; 76 77 father(e[0].u); 78 79 for(int i=0; i<m; ++i) { 80 int pv = father(e[i].v); 81 int pu = father(e[i].u); 82 if (pv != pu) { 83 if (rank_1[pv] < rank_1[pu]) { 84 parent[pv] = pu; // union pv -> pu 85 } 86 else { 87 parent[pu] = pv; // union pu -> pv 88 if (rank_1[pu] == rank_1[pv]) { 89 ++rank_1[pv]; 90 } 91 } 92 93 ++k; 94 95 if (e[i].t > ans) { 96 ans = e[i].t; 97 } 98 } 99 if (k==n-1) break; 100 } 101 102 cout << ans << endl; 103 104 return 0; 105 }
标签:parent,int,Kruskal,rank,生成,传输,201812,Edge,CCF 来源: https://www.cnblogs.com/sci-dev/p/11489022.html