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 } 

猜你喜欢

转载自www.cnblogs.com/sci-dev/p/11489022.html