poj 3164 通信网络 最小树状图

#include<cstdio>  
#include<cmath>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
const int inf=0x3f3f3f3f;  
const int maxn=1005;  
struct point  
{  
    double x,y;  
}p[maxn];  
struct node  
{  
    int u,v;  
    double len;  
}edge[maxn*maxn];  
int pre[maxn],id[maxn],vis[maxn];  
double in[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));  
}  
double dir_mst(int root,int n,int m)  
{  
    double ans=0;  
    while(1)  
    {  
        //先找出所有点的最小入边   
        /*memset(in,inf,sizeof(in)); //这样写会报错!*/  
        for(int i=0;i<n;++i)  
        {  
            in[i]=inf;  
        }  
        for(int i=0;i<m;++i)  
        {  
            int u=edge[i].u,v=edge[i].v;  
            if(edge[i].len<in[v]&&u!=v)  
            {  
                pre[v]=u;in[v]=edge[i].len;  
            }  
        }  
        for(int i=0;i<n;++i)  
        {  
            if(i==root)  
            {  
                continue;  
            }  
            if(in[i]==inf)  
            {  
                return -1;  //如果某点入度为零,必定找不到   
            }  
        }  
        //检查这些边是否构成了环   
        memset(id,-1,sizeof(id));  
        memset(vis,-1,sizeof(vis));  
        in[root]=0;  
        int cnt=0;  
        for(int i=0;i<n;++i)//标记环   
        {  
            ans+=in[i];  
            int v=i;  
            while(vis[v]!=i&&id[v]==-1&&v!=root)  
            {  
                vis[v]=i;  
                v=pre[v];  
            }  
            if(v!=root&&id[v]==-1)//缩点   
            {  
                for(int u=pre[v];u!=v;u=pre[u])  
                {  
                    id[u]=cnt;  
                }  
                id[v]=cnt++;  
            }  
        }  
        if(cnt==0)  
        {  
            break;//无环   
        }  
        for(int i=0;i<n;++i)  
        {  
            if(id[i]==-1)  
            {  
                id[i]=cnt++;  
            }  
        }  
        //建立新图   
        for(int i=0;i<m;++i)  
        {  
            int u=edge[i].u,v=edge[i].v;  
            edge[i].u=id[u];  
            edge[i].v=id[v];  
            if(id[u]!=id[v])  
            {  
                edge[i].len-=in[v];  
            }  
        }  
        n=cnt;  
        root=id[root];  
    }  
    return ans;  
}  
int main()  
{  
    int n,m;  
    while(~scanf("%d%d",&n,&m))  
    {  
        for(int i=0;i<n;++i)  
        {  
            scanf("%lf%lf",&p[i].x,&p[i].y);  
        }  
        for(int i=0;i<m;++i)  
        {  
            scanf("%d%d",&edge[i].u,&edge[i].v);  
            --edge[i].u;--edge[i].v;  
            if(edge[i].u!=edge[i].v)  
            {  
                edge[i].len=dis(p[edge[i].u],p[edge[i].v]);   
            }  
            else  
            {  
                edge[i].len=inf;  
            }  
        }  
        double ans=dir_mst(0,n,m);  
        if(ans==-1)  
        {  
            printf("poor snoopy\n");  
        }  
        else  
        {  
            printf("%.2f\n",ans);  
        }  
    }  
    return 0;  
}  
不知道原理是什么,只知道这样套模板就对了=-= 等回来明白了再改这篇博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值