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

 

你可能感兴趣的:(poj)