朱刘算法与最小树形图

参考:http://hi.baidu.com/yhxhqvnjombfpzq/item/5d93ef69ceb541176895e682

       http://hi.baidu.com/lydrainbowcat/item/5fbae3fb9c159c5ec8f33753(看这篇文章有助于理解缩点过程中对于权的处理,非常清晰)

想要自己写可是还是没有写出来,把这位同学的代码抄了一遍,终于弄懂了。。十分感谢。http://blog.sina.com.cn/s/blog_6af663940100ls4e.html

#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<string.h>
using namespace std;
#define MAXN 110
#define INF 1000000000
#define clr(a,b); memset(a,b,sizeof(a));
struct Node
{
    double x;
    double y;
}node[MAXN];
int n,m;
int tmp;
bool visited[MAXN],circle[MAXN];
int pre[MAXN];
double graph[MAXN][MAXN];
inline double dist(int i,int j)
{
    return sqrt((node[i].x-node[j].x)*(node[i].x-node[j].x)+(node[i].y-node[j].y)*(node[i].y-node[j].y));
}
inline double min(double a,double b)
{
    if(a<b)
    return a;
    return b;
}
void dfs(int u)  /*深搜判断是否能够到达每个结点*/
{
    if(visited[u])
    return;
    visited[u]=true;
    for(int i=1;i<=n;i++)
    {
        if(!visited[i]&&graph[u][i]!=INF)
        {
            dfs(i);
        }
    }
}
bool connect()
{
    dfs(1);
    for(int i=1;i<=n;i++)
    {
        if(!visited[i])
        return false;
    }
    return true;
}
double zhu_liu()
{
    double ans=0;int i,j,k;
    clr(circle,0);//如果某点被删除了,那么circle[i]=1
    while(1)
    {
        //求出除根节点以为每个结点入边的最小值
        for(i=2;i<=n;i++)
        {
            if(circle[i]) continue;
            graph[i][i]=INF; //把图中所有的自环都清除,这一点很重要
            pre[i]=i;  //初始化自己的前一个结点是自己
            for(j=1;j<=n;j++)
            {
                if(circle[j])
                continue;
                if(graph[j][i]<graph[pre[i]][i])
                {
                    pre[i]=j;
                }
            }
        }
        //遍历找环
        for(i=2;i<=n;i++)
        {
            if(circle[i])
            continue;
            j=i;
            clr(visited,false);
            while(!visited[j]&&j!=1)
            {
                visited[j]=true;
                j=pre[j];
            }
            if(j==1)
            continue;
            i=j;
            //把环的权值都加到ans里
            ans+=graph[pre[i]][i];
            for(j=pre[i];j!=i;j=pre[j])
            {
                ans+=graph[pre[j]][j];
                circle[j]=1; //只用i代表这个环,其他的点都删掉,缩点
            }
            for(j=1;j<=n;j++)
            {
                if(circle[j]) continue;
                if(graph[j][i]!=INF)
                graph[j][i]-=graph[pre[i]][i];
            }
            for(j=pre[i];j!=i;j=pre[j])
            {
                for(k=1;k<=n;k++)
                {
                    if(circle[k]) continue;
                    if(graph[j][k]!=INF)
                    graph[i][k]=min(graph[i][k],graph[j][k]);
                    if(graph[k][j]!=INF)
                    graph[k][i]=min(graph[k][i],graph[k][j] - graph[pre[j]][j]);
                }
            }
            break;
        }
        if(i>n)
        {
            for(j=2;j<=n;j++)
            {
                if(circle[j])
                continue;
                ans+=graph[pre[j]][j];
            }
            break;
        }
    }
    return ans;
}
int main()
{
    int i,j,u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%lf%lf",&node[i].x,&node[i].y);
        }
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            graph[i][j]=INF;
        }

    while(m--)
    {
        scanf("%d%d",&u,&v);
        graph[u][v]=dist(u,v);
    }
    clr(visited,false);
    if(!connect())
    printf("poor snoopy\n");
    else
    printf("%.2f\n",zhu_liu());
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/whatthefy/p/3188136.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值