有固定根的最小树形图求法O(VE):
首先消除自环,显然自环不在最小树形图中。然后判定是否存在最小树形图,以根为起点DFS一遍即可。、、
之后进行以下步骤。
设cost为最小树形图总权值。
0.置cost=0。
1.求最短弧集合Ao (一条弧就是一条有向边)
除源点外,为所有其他节点Vi,找到一条以Vi为终点的边,把它加入到集合Ao中。
(加边的方法:所有点到Vi的边中权值最小的边即为该加入的边,记prev[vi]为该边的起点,mincost[vi]为该边的权值)
2.检查Ao中的边是否会形成有向圈,有则到步骤3,无则到步骤4。
(判断方法:利用prev数组,枚举为检查过的点作为搜索的起点,做类似DFS的操作)
3.将有向环缩成一个点。
假设环中的点有(Vk1,Vk2,… ,Vki)总共i个,用缩成的点叫Vk替代,则在压缩后的图中,其他所有不在环中点v到Vk的距离定义如下:
gh[v][Vk]=min { gh[v][Vkj]-mincost[Vkj] } (1<=j<=i)而Vk到v的距离为
gh[Vk][v]=min { gh[Vkj][v] } (1<=j<=i)
同时注意更新prev[v]的值,即if(prev[v]==Vkj) prev[v]=Vk
另外cost=cost+mincost[Vkj] (1<=j<=i)
到步骤1.
4.cost加上Ao的权值和即为最小树形图总权值。
如要输出最小树形图较烦,没实现过。
找环O(V),收缩O(E),总复杂度O(VE)。
那幅对我有莫大帮助的流程图如下,
![](https://img-my.csdn.net/uploads/201209/08/1347073155_7796.jpg)
以上内容摘自该博客http://hi.baidu.com/yhxhqvnjombfpzq/item/5d93ef69ceb541176895e682
我下面的代码没有用DFS,而是直接从找最小入边开始。并寻找圈,如果不存在圈并且每一个点都存在一条权不为INF的入边,那么则存在一个最小树形图。如果出现一个点不存在一条入边,那么树形图不存在。
Transfer water
Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 2432 Accepted Submission(s): 901
First line of each case contains 4 integers n (1<=n<=1000), the number of the households, X (1<=X<=1000), Y (1<=Y<=1000), Z (1<=Z<=1000).
Each of the next n lines contains 3 integers a, b, c means the position of the i‐th households, none of them will exceeded 1000.
Then next n lines describe the relation between the households. The n+i+1‐th line describes the relation of the i‐th household. The line will begin with an integer k, and the next k integers are the household numbers that can build a water line from the i‐th household.
If n=X=Y=Z=0, the input ends, and no output for that.
2 10 20 30 1 3 2 2 4 1 1 2 2 1 2 0 0 0 0
30HintIn 3‐dimensional space Manhattan distance of point A (x1, y1, z1) and B(x2, y2, z2) is |x2‐x1|+|y2‐y1|+|z2‐z1|.#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> using namespace std; #define INF 0x3FFFFFF #define MAXN 2222 struct edge { int u,v,w; }e[99999999]; int a,b,c; int n,en; int pre[MAXN],in[MAXN],id[MAXN],vis[MAXN]; int x[MAXN],y[MAXN],z[MAXN]; int getdis(int i,int j) { return abs(x[i]-x[j])+abs(y[i]-y[j])+abs(z[i]-z[j]); } void add(int u,int v,int w) { e[en].u=u; e[en].v=v; e[en++].w=w; } int zl(int root ,int vn) { int ans=0; int cnt; while(1) { for(int i=0;i<vn;i++) in[i]=INF,id[i]=-1,vis[i]=-1; for(int i=0;i<en;i++) { if(in[e[i].v]>e[i].w && e[i].u!=e[i].v) { pre[e[i].v]=e[i].u; in[e[i].v]=e[i].w; } } in[root]=0; pre[root]=root; for(int i=0;i<vn;i++) { ans+=in[i]; if(in[i]==INF)//这一步可以看出是否存在这样一棵树形图,因此可以略去DFS return -1; } cnt=0; for(int i=0;i<vn;i++) { if(vis[i]==-1) { int t=i; while(vis[t]==-1) { vis[t]=i; t=pre[t]; } if(vis[t]!=i || t==root) continue; for(int j=pre[t];j!=t;j=pre[j]) id[j]=cnt; id[t]=cnt++; } } if(cnt==0) break; for(int i=0;i<vn;i++) if(id[i]==-1) id[i]=cnt++; for(int i=0;i<en;i++) { int u,v; u=e[i].u; v=e[i].v; e[i].u=id[u]; e[i].v=id[v]; e[i].w-=in[v]; } vn=cnt; root=id[root]; } return ans; } void solve() { int cnt,j; en=0; for(int i=1;i<=n;i++) { scanf("%d%d%d",&x[i],&y[i],&z[i]); add(0,i,z[i]*a); } for(int i=1;i<=n;i++) { scanf("%d",&cnt); for(int k=1;k<=cnt;k++) { scanf("%d",&j); if(i==j) continue; if(z[i]>=z[j]) add(i,j,getdis(i,j)*b); else add(i,j,getdis(i,j)*b+c); } } int ans=zl(0,n+1); if(ans==-1) { printf("poor XiaoA\n"); return; } printf("%d\n",ans); } int main() { while(scanf("%d%d%d%d",&n,&a,&b,&c)!=EOF && n+a+b+c) solve(); return 0; }