poj 3164(最小树形图)
题目链接:http://poj.org/problem?id=3164
思路:朱刘算法,模版题。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define MAXN 111 8 #define inf 1<<30 9 10 struct Edge{ 11 int u,v; 12 double w; 13 }edge[MAXN*MAXN]; 14 15 struct Node { 16 double x,y; 17 } node[MAXN]; 18 19 int n,m; 20 double In[MAXN]; 21 int pre[MAXN],visited[MAXN],ID[MAXN]; 22 //root表示根结点,n是顶点树,m是边数 23 //最小树形图邻接表版本,三步走,找最小入弧,找有向环,缩环为点 24 double Directed_MST(int root,int n,int m) 25 { 26 int u,v,i,ansi; 27 double cnt=0; 28 while(true) { 29 //找最小入边 30 for(i=0; i<n; i++)In[i]=inf; 31 for(i=0; i<m; i++) { 32 u=edge[i].u; 33 v=edge[i].v; 34 if(edge[i].w<In[v]&&u!=v) { 35 pre[v]=u;//u->v; 36 if(u==root)//记录是root从哪一条边到有效点的(这个点就是实际的起点) 37 ansi=i; 38 In[v]=edge[i].w; 39 } 40 } 41 for(i=0; i<n; i++) { 42 if(i==root)continue; 43 if(In[i]==inf)return -1;//说明存在点没有入边 44 } 45 //找环 46 int cntcode=0; 47 memset(visited,-1,sizeof(visited)); 48 memset(ID,-1,sizeof(ID)); 49 In[root]=0; 50 //标记每一个环 51 for(i=0; i<n; i++) { 52 cnt+=In[i]; 53 v=i; 54 while(visited[v]!=i&&ID[v]==-1&&v!=root) { 55 visited[v]=i; 56 v=pre[v]; 57 } 58 //说明此时找到一个环 59 if(v!=root&&ID[v]==-1) { 60 //表示这是找到的第几个环,给找到的环的每个点标号 61 for(u=pre[v]; u!=v; u=pre[u]) { 62 ID[u]=cntcode; 63 } 64 ID[v]=cntcode++; 65 } 66 } 67 if(cntcode==0)break;//说明不存在环 68 for(i=0; i<n; i++) { 69 if(ID[i]==-1) 70 ID[i]=cntcode++; 71 } 72 //缩点,重新标记 73 for(i=0; i<m; i++) { 74 int v=edge[i].v; 75 edge[i].u=ID[edge[i].u]; 76 edge[i].v=ID[edge[i].v]; 77 //说明原先不在同一个环 78 if(edge[i].u!=edge[i].v) { 79 edge[i].w-=In[v]; 80 } 81 } 82 n=cntcode; 83 root=ID[root]; 84 } 85 return cnt; 86 } 87 88 double Get_dist(int i,int j) 89 { 90 double d1=(node[i].x-node[j].x)*(node[i].x-node[j].x); 91 double d2=(node[i].y-node[j].y)*(node[i].y-node[j].y); 92 return sqrt(d1+d2); 93 } 94 95 int main() 96 { 97 double ans; 98 while(~scanf("%d%d",&n,&m)){ 99 for(int i=0;i<n;i++)scanf("%lf%lf",&node[i].x,&node[i].y); 100 for(int i=0;i<m;i++){ 101 scanf("%d%d",&edge[i].u,&edge[i].v); 102 edge[i].u--; 103 edge[i].v--; 104 if(edge[i].u!=edge[i].v)edge[i].w=Get_dist(edge[i].u,edge[i].v); 105 else edge[i].w=inf;//消除自环 106 } 107 ans=Directed_MST(0,n,m); 108 if(ans==-1){ 109 puts("poor snoopy"); 110 }else 111 printf("%.2f\n",ans); 112 } 113 return 0; 114 }