链接: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