POJ 3164 Command Network(最小树形图模板题)

最小树形图 

大神博客

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
typedef long long LL;
const int maxn =100+5;
const int maxe = 15000+5;
const int INF = 460002326;
const int mod = 1000000009;
double map[maxn][maxn];
double zhuliu(int n)
{
    bool visit[maxn];
    bool flag[maxn];//缩点标记为ture,则该点已经被缩掉,否则依然存在
    int pre[maxn];
    double sum=0;
    int i,j,k;
    for(i=0; i<n; i++)
    {
        flag[i]=false;
        map[i][i]=INF;
    }
    pre[0]=0;
    while(true)
    {
        //求最短弧集合E0
        for(i=1; i<n; i++)
        {
            if(flag[i]) continue;
            pre[i]=i;
            for(j=0; j<n; j++)
            {
                if(!flag[j]&&map[j][i]<map[pre[i]][i])
                    pre[i]=j;
            }
            if(pre[i]==i)
                return -1;
        }
        //检查E0
        for(i=1; i<n; i++)
        {
            if(flag[i]) continue;
            //从当前点开始找环
            for(j=0; j<n; j++)
                visit[j]=false;
            visit[0]=true;
            j=i;
            do
            {
                visit[j]=true;
                j=pre[j];
            }
            while(!visit[j]);
            if(!j) continue; //没有找到环
            //收缩G中的有向环
            i=j;
            ///将整个环的权值保存,累计入原图的最小树形图
            do
            {
                sum+=map[pre[j]][j];
                j=pre[j];
            }
            while(j!=i);
            j=i;
            //对与环上的点有关的边,修改边权
            do
            {
                for(k=0; k<n; k++)
                {
                    if(!flag[k]&&map[k][j]<INF&&k!=pre[j])
                        map[k][j]-=map[pre[j]][j];
                }
                j=pre[j];
            }
            while(j!=i);
            //缩点,将整个环缩成i号点,所有与环上的点有关的边转移到点i
            for(j=0; j<n; j++)
            {
                if(j==i) continue;
                for(k=pre[i]; k!=i; k=pre[k])
                {
                    if(map[k][j]<map[i][j])
                        map[i][j]=map[k][j];
                    if(map[j][k]<map[j][i])
                        map[j][i]=map[j][k];
                }
            }
            //标记环上其他的点为被缩掉
            for(j=pre[i]; j!=i; j=pre[j]) flag[j]=true;
            //当前环缩点结束,形成新的图G1,跳出继续求G1的最小树形图
            break;
        }
        //如果所有的点都被检查切没有环存在,现在的环最短弧几何E0就是最小树形图,
        //累计入sum,算法结束
        if(i==n)
        {
            for(i=1; i<n; i++)
            {
                if(!flag[i])
                    sum+=map[pre[i]][i];
            }
            break;
        }
    }
    return sum;
}
double x[maxn],y[maxn];
double mat(int a,int b)
{
    return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
int main()
{
    int n,m;
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {

        for(int i=0; i<101; i++)
            for(int j=0; j<101; j++)
                map[i][j]=INF;
        for(int i=0; i<n; i++)
            scanf("%lf%lf",&x[i],&y[i]);
        for(int i=0; i<m; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            a--,b--;
            map[a][b]=mat(a,b);
        }
        double ans=zhuliu(n);
        if(ans<0)
            puts("poor snoopy");
        else printf("%.2lf\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值