poj 3164 最小树形图 初识朱刘算法

本文介绍了一个基于朱刘算法解决最小树形图问题的方法。通过计算点间的距离并使用特定策略来构建无环路的树形结构,从而找到连接所有点所需的最短电线长度。文章详细解释了算法的主要步骤,并提供了完整的C++实现代码。

传送门

题意:给你n个点坐标,m个连接关系,问从1要能到所以点至少要铺设多少长的电线。

个人心得:第一次做最小树形图。

思路:前人博客

关于朱刘算法,主要思路就是一下几步:

1、对于每个点(除根节点),找最小入边。

2、判环,将环所成新点。

3、重建图。然后重复以上步骤直到没环。

详见链接。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 1<<30
using namespace std;
struct node
{
    double x,y;
}p[105];
struct edge
{
    int u,v;
    double l;
}e[10005];
int m,n,id[105],vis[105],pre[105];
double in[105];
double DMST(int root,int vn,int en)
{
    int u,v;
    double ans=0;
    while(1)
    {
        memset(id,-1,sizeof(id));
        memset(vis,-1,sizeof(vis));
        int cnt=0;
        for(int i=1;i<=vn;i++)in[i]=maxn;
        for(int i=1;i<=en;i++)
        {
            u=e[i].u;
            v=e[i].v;
            if(e[i].l<in[v]&&u!=v)
            {
                in[v]=e[i].l;
                pre[v]=u;
            }
        }
        for(int i=1;i<=vn;i++)
        {
            if(i==root)continue;
            else if(in[i]==maxn)return -1;
        }
        in[root]=0;
        for(int i=1;i<=vn;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)
            {
                u=v;
                do
                {
                    id[u]=cnt+1;
                    u=pre[u];
                }while(u!=v);
                cnt++;
            }
        }
        if(cnt==0)break;
        for(int i=1;i<=vn;i++)
        {
            if(id[i]==-1)
            {
                id[i]=++cnt;
            }
        }
        for(int i=1;i<=en;i++)
        {
            u=e[i].u;
            v=e[i].v;
            e[i].u=id[u];
            e[i].v=id[v];
            if(id[u]!=id[v])e[i].l-=in[v];
        }
        vn=cnt;
        root=id[root];
    }
    return ans;
}
int main()
{
    int u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            e[i].u=u;
            e[i].v=v;
            e[i].l=sqrt((p[u].x-p[v].x)*(p[u].x-p[v].x)+(p[u].y-p[v].y)*(p[u].y-p[v].y));
        }
        double ans=DMST(1,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、付费专栏及课程。

余额充值