poj 3164 最小树形图

思路:就是裸的最小树形图~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define Maxn 110
#define LL double
#define inf 1e9
using namespace std;
int pre[Maxn],id[Maxn],vi[Maxn],num;
LL in[Maxn];
struct Edge{
    int u,v;
     LL val;
}edge[Maxn*Maxn];
struct Point{
    double x,y;
}p[Maxn];
double Dis(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void add(int u,int v,LL val)
{
    edge[num].u=u,edge[num].v=v,edge[num++].val=val;
}
LL directed_MST(int root,int n,int e)
{
    int i,j,u,v,cnt=0;
    LL ans=0;
    while(1)
    {
        for(i=1;i<=n;i++) in[i]=inf;
        for(i=0;i<e;i++)//找最小入边
        {
            u=edge[i].u;
            v=edge[i].v;
            if(in[v]>edge[i].val&&v!=u)
            {
                in[v]=edge[i].val;
                pre[v]=u;
            }
        }
        for(i=1;i<=n;i++)
        {
            if(i==root) continue;
            if(in[i]==inf) return -1;
        }
        memset(vi,-1,sizeof(vi));
        memset(id,-1,sizeof(id));
        cnt=0;
        in[root]=0;
        for(i=1;i<=n;i++)//枚举每个可能是环上的点
        {
            ans+=in[i];
            v=i;
            while(vi[v]!=i&&id[v]==-1&&v!=root)
            {
                vi[v]=i;v=pre[v];
            }
            if(v!=root&&id[v]==-1)//如果退出上个循环的条件不是v==root,就是vi[i]==i,即找到了环
            {
                id[v]=++cnt;
                for(u=pre[v];u!=v;u=pre[u])//对环进行统一标号
                    id[u]=cnt;
            }
        }
        if(cnt==0) break;//无环 ,退出
        for(i=1;i<=n;i++) if(id[i]==-1) id[i]=++cnt;
        for(i=0;i<e;i++)//进行缩点,并修改每条边的权值。
        {
            v=edge[i].v;
            edge[i].u=id[edge[i].u];
            edge[i].v=id[edge[i].v];
            if(edge[i].u!=edge[i].v)
                edge[i].val-=in[v];
        }
        n=cnt;
        root=id[root];
    }
    return ans;
}
int main()
{
    int i,j,n,m,a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        num=0;
        for(i=1;i<=n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            if(a!=b)
            add(a,b,Dis(p[a],p[b]));
        }
        double ans=directed_MST(1,n,num);
        if(ans==-1)
            printf("poor snoopy\n");
        else
            printf("%.2lf\n",ans);
    }
    return 0;
}

 

posted @ 2013-07-25 17:06  fangguo  阅读(147)  评论(0编辑  收藏  举报