最小树形图
http://blog.csdn.net/wsniyufang/article/details/6747392
题意:给出一个有向图,求以root为根的最小树形图
// File Name: 3164.cpp // Author: zlbing // Created Time: 2013/2/17 18:46:24 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define MAXN 105 #define INF 0x3f3f3f3f #define CL(x,v); memset(x,v,sizeof(x)); struct point{ int x,y; }p[MAXN]; double dis(point a,point b) { return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } struct Edge{ int from,to; double dist; }edges[MAXN*MAXN]; double In[MAXN]; int pre[MAXN],ID[MAXN],vis[MAXN]; double Directed_MST(int root,int n,int m) { double ans=0; while(true) { //1、找最小入边 for(int i=0;i<n;i++)In[i]=INF; for(int i=0;i<m;i++) { int u=edges[i].from; int v=edges[i].to; if(edges[i].dist<In[v]&&u!=v) { pre[v]=u; In[v]=edges[i].dist; } } //2、判断是否有最小生成树 for(int i=0;i<n;i++) { if(i==root)continue; if(In[i]==INF)return -1; } //3、找环 int cntnode=0; CL(ID,-1); CL(vis,-1); In[root]=0; for(int i=0;i<n;i++) { ans+=In[i]; int v=i; while(vis[v]!=i&&ID[v]==-1&&v!=root) { vis[v]=i; v=pre[v]; } if(v!=root&&ID[v]==-1) { for(int u=pre[v];u!=v;u=pre[u]) { ID[u]=cntnode; } ID[v]=cntnode++; } } if(cntnode==0)break; for(int i=0;i<n;i++) if(ID[i]==-1) ID[i]=cntnode++; //4、缩点,重新标记 for(int i=0;i<m;i++) { int v=edges[i].to; edges[i].from=ID[edges[i].from]; edges[i].to=ID[edges[i].to]; if(edges[i].from!=edges[i].to) { edges[i].dist-=In[v]; } } n=cntnode; root=ID[root]; } return ans; } int main(){ int n,m; while(~scanf("%d%d",&n,&m)) { for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); int a,b; for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); a--,b--; edges[i].from=a; edges[i].to=b; if(a!=b) edges[i].dist=dis(p[a],p[b]); else edges[i].dist=INF; } double ans=Directed_MST(0,n,m); if(ans==-1) printf("poor snoopy\n"); else printf("%.2lf\n",ans); } return 0; }