最小树形图(有向图的最小生成树)
求最小树形图
算法:朱刘算法
下面纠正几个易错错误和较难理解的地方(可结合程序判断)
1.所缩的环为为所选择的边所形成的环,并不是图中所有的环。
2.缩环后可能形成新的环。
3.缩环后减权不改变最小树形图的大小,减权是为了删边(所删的边在这之前已经加了,但并不属于最小树形图,所以要删去)。
相关的题目 poj3164
代码
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cmath> 5 #include <string> 6 #include <cstring> 7 #include <algorithm> 8 using namespace std; 9 10 const int Inf=2000000000; 11 const int Max=105; 12 struct Point 13 { 14 double x,y; 15 }p[Max]; 16 struct node 17 { 18 int u,v; 19 double w; 20 }e[Max*Max]; 21 int pre[Max],id[Max],vis[Max],n,m; 22 double Minc[Max]; 23 24 double dis(Point a,Point b) 25 { 26 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 27 } 28 29 double Directed_MST(int root,int V,int E) 30 { 31 int u,v,cnt; 32 double ret=0; 33 while(true) 34 { 35 for(int i=0; i<V; i++) Minc[i]=Inf; 36 for(int i=0; i<E; i++) 37 { 38 u=e[i].u;v=e[i].v; 39 if(e[i].w<Minc[v]&&u!=v) 40 pre[v]=u,Minc[v]=e[i].w; 41 } 42 for(int i=0; i<V; i++) 43 { 44 if(i==root) continue; 45 if(Minc[i]==Inf) return -1; 46 } 47 cnt=0;Minc[root]=0; 48 memset(id,-1,sizeof(id)); 49 memset(vis,-1,sizeof(vis)); 50 for(int i=0; i<V; i++) 51 { 52 ret+=Minc[i];v=i; 53 while(vis[v]!=i&&id[v]==-1&&v!=root) vis[v]=i,v=pre[v]; 54 if(v!=root&&id[v]==-1) 55 { 56 for(int u=pre[v]; u!=v; u=pre[u]) 57 id[u]=cnt; 58 id[v]=cnt++; 59 } 60 } 61 if(cnt==0) break; 62 for(int i=0; i<V; i++) 63 if(id[i]==-1) 64 id[i]=cnt++; 65 for(int i=0; i<E; i++) 66 { 67 u=e[i].u,v=e[i].v; 68 e[i].u=id[u],e[i].v=id[v]; 69 if(id[u]!=id[v]) e[i].w-=Minc[v]; 70 } 71 V=cnt;root=id[root]; 72 } 73 return ret; 74 } 75 76 int main() 77 { 78 while(scanf("%d%d",&n,&m)==2) 79 { 80 for(int i=0; i<n; i++) scanf("%lf%lf",&p[i].x,&p[i].y); 81 for(int i=0; i<m; i++) 82 { 83 scanf("%d%d",&e[i].u,&e[i].v); 84 e[i].u--,e[i].v--; 85 if(e[i].u!=e[i].v) e[i].w=dis(p[e[i].u],p[e[i].v]); 86 else e[i].w=Inf; 87 } 88 double ans=Directed_MST(0,n,m); 89 if(ans==-1) printf("poor snoopy\n"); 90 else printf("%.2f\n",ans); 91 } 92 return 0; 93 }