hdu 4009 Transfer water(最小树形图生成森林)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4009

  再来最小树形图的题,拿来练习打最小树形图的朱刘算法.....

  这题看懂了以后想不到办法解决,于是就喵了喵别人的代码,才发现原来不仅网络流的构图要技巧,最小树形图的、解决也需要技巧的。这让我大开眼界了!

  这题的构图跟不定根的构图差不多,不过这里可以有多个根,也就是要求有向图的最小生成森林了。看上去还有点像网络流,不过好像不能用网络流来解决。

  看懂了构图以后,就唯有将这题当作是练手了,剩下的就是体力活儿了.....最小树形图的代码挺多陷阱的,尤其要注意寻找环那部分的代码,因为那里比较容易打错变量。另外还有环的判定条件,写漏了也会产生巨大的影响!最后就是更新边,以及找最小边权的时候要注意判起点和终点是否相同。

  下面是这题的代码,运行速度挺快的,890ms,内存消耗也相当小,5MB!

View Code
  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <cmath>
  5 
  6 typedef __int64 ll;
  7 const int inf = 0x7f7f7f7f;
  8 const int maxn = 1001;
  9 
 10 struct edge{
 11     int s, t;
 12     int c;
 13     void add(int a, int b, int cost){
 14         s = a;
 15         t = b;
 16         c = cost;
 17     }
 18 }E[maxn * maxn];
 19 struct point{
 20     int x, y, z;
 21     int operator - (const point &a) {
 22         return abs(x - a.x) + abs(y - a.y) + abs(z - a.z);
 23     }
 24 }P[maxn];
 25 int min_cost;
 26 int vis[maxn], fold[maxn], cost[maxn], pre[maxn];
 27 
 28 bool make_tree(int root, int v, int e){
 29     int i, j, k, cnt;
 30     int s, t;
 31 
 32     min_cost = 0;
 33     while (true){
 34         for (i = 0; i < v; i++){
 35             cost[i] = inf;
 36         }
 37         for (i = 0; i < e; i++){
 38             s = E[i].s;
 39             t = E[i].t;
 40 
 41             if (cost[t] > E[i].c && s != t){
 42                 cost[t] = E[i].c;
 43                 pre[t] = s;
 44             }
 45         } // find min-arc
 46 
 47         cost[root] = 0;
 48         for (i = 0; i < v; i++){
 49             min_cost += cost[i];
 50             vis[i] = fold[i] = -1;
 51             if (cost[i] == inf && i != root) return false;
 52         } // whether it can be built
 53 
 54         cnt = 0;
 55         for (i = 0; i < v; i++){
 56             j = i;
 57             for (vis[j] = i, j = pre[j]; vis[j] != i && fold[j] == -1 && j != root; vis[j] = i, j = pre[j]);
 58 
 59             if (fold[j] != -1 || j == root) continue;
 60             k = j;
 61             for (fold[k] = cnt, k = pre[k]; k != j; fold[k] = cnt, k = pre[k]);
 62             cnt++;
 63         } // find circle
 64 
 65         if (!cnt) return true; // no circle, tree built
 66 
 67         for (i = 0; i < v; i++){
 68             if (fold[i] == -1) fold[i] = cnt++;
 69         } // re-number vexs
 70 
 71         for (i = 0; i < e; i++){
 72             s = E[i].s;
 73             t = E[i].t;
 74 
 75             E[i].s = fold[s];
 76             E[i].t = fold[t];
 77             if (E[i].s != E[i].t){
 78                 E[i].c -= cost[t];
 79             }
 80         } // refresh arcs
 81         v = cnt;
 82         root = fold[root];
 83     }
 84 }
 85 
 86 
 87 
 88 
 89 
 90 
 91 bool deal(){
 92     int n, X, Y, Z;
 93     int k, m = 0, r;
 94 
 95     scanf("%d%d%d%d", &n, &X, &Y, &Z);
 96     if (!n && !X && !Y && !Z) return false;
 97 
 98     for (int i = 1; i <= n; i++){
 99         scanf("%d%d%d", &P[i].x, &P[i].y, &P[i].z);
100         E[m].add(0, i, P[i].z * X);
101         m++;
102     }
103     for (int i = 1; i <= n; i++){
104         scanf("%d", &k);
105         while (k--){
106             scanf("%d", &r);
107             if (r != i){
108                 if (P[i].z >= P[r].z) E[m].add(i, r, (P[i] - P[r]) * Y);
109                 else E[m].add(i, r, (P[i] - P[r]) * Y + Z);
110                 m++;
111             }
112         }
113     }
114 
115     if (make_tree(0, n + 1, m)) printf("%d\n", min_cost);
116     else puts("poor XiaoA");
117 
118     return true;
119 }
120 
121 int main(){
122     #ifndef ONLINE_JUDGE
123     freopen("in", "r", stdin);
124     #endif
125     while (deal());
126 
127     return 0;
128 }

  最小树形图就先练这几题。模板测试通过,以后能放心用了~

——written by Lyon

原文地址:https://www.cnblogs.com/LyonLys/p/hdu_4009_Lyon.html