题目链接:http://poj.org/problem?id=3164
裸的最小树形图,用朱—刘算法解决,具体实现过程如下:算法一开始先判断从固定根开始是否可达所有原图中的点,若不可,则一定不存在最小树形图。这一步是一个很随便的搜索,写多搓都行,不加废话。第二步,遍历所有的边,从中找出除根结点外各点的最小入边,累加权值,构成新图。接着判断该图是否存在环。若不存在,则该图便是所求最小树型图,当前权为最小权。否则对环缩点,然后回到第二步继续判断。简化就是三个过程:找边—>找环—>缩点;
算法流程图:
参考样例:
代码实现有很多种方法,为了兼顾代码的长度和效率,我选择了O(VE)的写法。
1 //STATUS:C++_AC_110MS_244KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 using namespace std; 13 #define LL __int64 14 #define pdi pair<double,int> 15 #define Max(a,b) ((a)>(b)?(a):(b)) 16 #define Min(a,b) ((a)<(b)?(a):(b)) 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define lson l,mid,rt<<1 19 #define rson mid+1,r,rt<<1|1 20 const int N=110,M=1000000,INF=0x3f3f3f3f,MOD=1999997; 21 const LL LLNF=0x3f3f3f3f3f3f3f3fLL; 22 const double DNF=100000000000; 23 24 struct Node{ 25 double x,y; 26 }nod[N]; 27 struct Edge{ 28 int u,v; 29 double w; 30 }e[N*N]; 31 int pre[N],id[N],vis[N]; 32 double minw[N]; 33 int n,m; 34 35 inline double dist(Node &a,Node &b) 36 { 37 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 38 } 39 40 double zhu_liu(int root) 41 { 42 int i,cou,u,v,k; 43 double ans=0; 44 while(1) 45 { 46 //init 47 mem(pre,-1); 48 for(i=1;i<=n;i++)minw[i]=DNF; 49 for(i=0;i<m;i++){ 50 u=e[i].u; 51 v=e[i].v; 52 if(e[i].w<minw[v] && u!=v){ 53 pre[v]=u; 54 minw[v]=e[i].w; 55 } 56 } 57 pre[root]=-1;minw[root]=0; 58 for(cou=0,i=1;i<=n;i++) 59 if(pre[i]==-1 && i!=root)cou++; 60 else ans+=minw[i]; 61 if(cou)return -1; 62 //cheack the circle 63 mem(vis,0); 64 mem(id,0); 65 for(i=1,k=0;i<=n;i++){ 66 if(id[i])continue; 67 u=i; 68 while(u!=-1 && !id[u] && vis[u]!=i){ 69 vis[u]=i; 70 u=pre[u]; 71 } 72 if(u!=-1 && !id[u] && vis[u]==i){ 73 k++; 74 while(id[u]!=k){ 75 id[u]=k; 76 u=pre[u]; 77 } 78 } 79 } 80 if(!k)break; 81 for(i=1;i<=n;i++)if(!id[i])id[i]=++k; 82 //eliminate circle 83 for(i=0;i<m;i++){ 84 e[i].w-=minw[e[i].v]; 85 e[i].u=id[e[i].u]; 86 e[i].v=id[e[i].v]; 87 } 88 n=k; 89 root=id[root]; 90 } 91 return ans; 92 } 93 94 int main() 95 { 96 // freopen("in.txt","r",stdin); 97 int i,j,a,b; 98 double c,ans; 99 while(scanf("%d%d",&n,&m)!=EOF) 100 { 101 for(i=1;i<=n;i++) 102 scanf("%lf%lf",&nod[i].x,&nod[i].y); 103 for(i=0;i<m;i++){ 104 scanf("%d%d",&a,&b); 105 c=dist(nod[a],nod[b]); 106 e[i].u=a,e[i].v=b,e[i].w=c; 107 } 108 109 ans=zhu_liu(1); 110 if(ans>=0)printf("%.2lf\n",ans); 111 else printf("poor snoopy\n"); 112 } 113 return 0; 114 }