POJ 3164 Command Network(最小树形图+朱刘算法)

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
const int maxn=100+5;
const int maxm=10000+5;
double inf;
double x[maxn],y[maxn];
int s[maxm],e[maxm];
double dis[maxm],in[maxn];
int pre[maxn],color[maxn],vis[maxn];
int n,m;
void MDST(int root)
{
    double ans=0;
    while(true)
    {
        memset(in,127,sizeof(in));
        memset(pre,-1,sizeof(pre));
        //选最短边
        for(int i=1;i<=m;i++){
            if(dis[i]<in[e[i]]&&s[i]!=e[i]){
                pre[e[i]]=s[i];in[e[i]]=dis[i];
            }
        }
        //如果有第二个点入度为0,那么最小树形图不存在
        for(int i=1;i<=n;i++) if(pre[i]==-1&&i!=root) {printf("poor snoopy\n");return ;}
        int cnt=0;in[root]=0;
        memset(color,-1,sizeof(color));   
        memset(vis,-1,sizeof(vis));
        for(int i=1;i<=n;i++){
            int u,v=i;ans+=in[i];
            while(v!=root&&vis[v]==-1) {vis[v]=i;v=pre[v];}//找环
            if(v!=root&&vis[v]==i)
                for(color[v]=++cnt,u=pre[v];u!=v;u=pre[u]) color[u]=cnt;//给环染色
        }
        if(!cnt) break;//无环
        for(int i=1;i<=n;i++) if(color[i]==-1) color[i]=++cnt;//给剩余的点染色
        //处理图,断开环上的in[i]边,其他进入边全部-in[i]
        for(int i=1;i<=m;i++){
            int u=s[i],v=e[i];
            s[i]=color[u];e[i]=color[v];
            if(color[u]!=color[v]) dis[i]-=in[v];
        }
        n=cnt;root=color[root];//更新图
    }
    printf("%.2f\n",ans);
}
int main()
{
    memset(in,127,sizeof(in));inf=in[1];
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]);
        for(int i=1;i<=m;i++) {
            scanf("%d%d",&s[i],&e[i]);
            dis[i]=(s[i]==e[i]?inf:hypot(x[s[i]]-x[e[i]],y[s[i]]-y[e[i]]));
        }
        MDST(1);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值