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 }
View Code

 

posted @ 2013-08-24 16:53  ihge2k  阅读(377)  评论(0编辑  收藏  举报