您的位置:首页 > Web前端

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

2012-08-11 01:31 411 查看
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4009

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

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

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

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

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

View Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

typedef __int64 ll;
const int inf = 0x7f7f7f7f;
const int maxn = 1001;

struct edge{
int s, t;
int c;
void add(int a, int b, int cost){
s = a;
t = b;
c = cost;
}
}E[maxn * maxn];
struct point{
int x, y, z;
int operator - (const point &a) {
return abs(x - a.x) + abs(y - a.y) + abs(z - a.z);
}
}P[maxn];
int min_cost;
int vis[maxn], fold[maxn], cost[maxn], pre[maxn];

bool make_tree(int root, int v, int e){
int i, j, k, cnt;
int s, t;

min_cost = 0;
while (true){
for (i = 0; i < v; i++){
cost[i] = inf;
}
for (i = 0; i < e; i++){
s = E[i].s;
t = E[i].t;

if (cost[t] > E[i].c && s != t){
cost[t] = E[i].c;
pre[t] = s;
}
} // find min-arc

cost[root] = 0;
for (i = 0; i < v; i++){
min_cost += cost[i];
vis[i] = fold[i] = -1;
if (cost[i] == inf && i != root) return false;
} // whether it can be built

cnt = 0;
for (i = 0; i < v; i++){
j = i;
for (vis[j] = i, j = pre[j]; vis[j] != i && fold[j] == -1 && j != root; vis[j] = i, j = pre[j]);

if (fold[j] != -1 || j == root) continue;
k = j;
for (fold[k] = cnt, k = pre[k]; k != j; fold[k] = cnt, k = pre[k]);
cnt++;
} // find circle

if (!cnt) return true; // no circle, tree built

for (i = 0; i < v; i++){
if (fold[i] == -1) fold[i] = cnt++;
} // re-number vexs

for (i = 0; i < e; i++){
s = E[i].s;
t = E[i].t;

E[i].s = fold[s];
E[i].t = fold[t];
if (E[i].s != E[i].t){
E[i].c -= cost[t];
}
} // refresh arcs
v = cnt;
root = fold[root];
}
}

bool deal(){
int n, X, Y, Z;
int k, m = 0, r;

scanf("%d%d%d%d", &n, &X, &Y, &Z);
if (!n && !X && !Y && !Z) return false;

for (int i = 1; i <= n; i++){
scanf("%d%d%d", &P[i].x, &P[i].y, &P[i].z);
E[m].add(0, i, P[i].z * X);
m++;
}
for (int i = 1; i <= n; i++){
scanf("%d", &k);
while (k--){
scanf("%d", &r);
if (r != i){
if (P[i].z >= P[r].z) E[m].add(i, r, (P[i] - P[r]) * Y);
else E[m].add(i, r, (P[i] - P[r]) * Y + Z);
m++;
}
}
}

if (make_tree(0, n + 1, m)) printf("%d\n", min_cost);
else puts("poor XiaoA");

return true;
}

int main(){
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
#endif
while (deal());

return 0;
}


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

——written by Lyon
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: