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;

}

 

你可能感兴趣的:(poj)