最小树形图——朱刘算法

首先问一个问题  最小生成树是用来解决有向图还是无向图问题的

最小生成树详解  见     https://blog.csdn.net/ZCY19990813/article/details/81503525

。。。。要是你回答无向图的话  可以往下面看啦

最小树形图是用来解决有向图的最小生成树问题(unidirectional 单向的)

性质:最小树形图基于贪心和缩点的思想。

正在看这篇文章    https://blog.csdn.net/lianai911/article/details/45462361

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<limits.h>
using namespace std;
const int MAXN = 110;
const int MAXM = 10010;

struct Node//存放图
{
    int from;
    int to;
    double w;
}Edges[MAXM];

struct Node1
{
    double x;
    double y;
};
Node1 Point[MAXN];

double Dist(Node1 a, Node1 b)
{
    double x = a.x - b.x;
    double y = a.y - b.y;
    return sqrt(x*x+y*y);
}

int pre[MAXN],vis[MAXN],flag[MAXN];
//flag标记缩点,标记为true,则该点被缩掉
double In[MAXN],sum;

double ZhuLiu(int root,int N,int M)
{
    sum = 0;    //存放最小树形图
    while(true)
    {
        //求最短弧集合
        for(int i = 0; i < N; ++i)
            In[i] = INT_MAX;
        for(int i = 0; i < M; ++i)
        {
            int u = Edges[i].from;
            int v = Edges[i].to;
            if(Edges[i].w < In[v] && u != v)
            {
                pre[v] = u;//v为终点,pre[v]存放起点
                In[v] = Edges[i].w;//权值最小的边
            }
        }

        for(int i = 0; i < N; ++i)//如果存在除root以外的孤立点,则不存在最小树形图
        {
            if(i == root)
                continue;
            if(In[i] == INT_MAX)
                return -1;
        }
        int CntNode = 0;    //新图编号
        memset(flag,-1,sizeof(flag));
        memset(vis,-1,sizeof(vis));
        In[root] = 0;
        for(int i = 0; i < N; ++i)   //找环,标记每个环
        {
            sum += In[i];
            int v = i;
            while(vis[v]!=i && flag[v]==-1 && v!=root)//每个点寻找其前序点,要么最终寻找至根部,要么找到一个环
            {
                vis[v] = i;
                v = pre[v];
            }
            if(v != root && flag[v] == -1)  //新图重新编号
            {
                for(int u = pre[v]; u != v; u = pre[u])
                    flag[u] = CntNode;
                flag[v] = CntNode++;
            }
        }
        if(CntNode == 0)    //无环,跳出
            break;
        for(int i = 0; i < N; ++i)  //缩点
        {
            if(flag[i] == -1)
                flag[i] = CntNode++;
        }
        for(int i = 0; i < M; ++i)  //建立新图,更新其他点到环的距离
        {
            int v = Edges[i].to;
            Edges[i].from = flag[Edges[i].from];
            Edges[i].to = flag[Edges[i].to];
            if(Edges[i].from != Edges[i].to)
                Edges[i].w -= In[v];
        }
        N = CntNode;
        root = flag[root];
    }
    return sum;
}

int main()
{
    int x,y,N,M;
    while(~scanf("%d%d",&N,&M))
    {
        int id = 0;
        for(int i = 0; i < N; ++i)
            scanf("%lf%lf",&Point[i].x,&Point[i].y);
        for(int i = 0; i < M; ++i)
        {
            scanf("%d%d",&x,&y);
            if(x == y)
                continue;
            x--;
            y--;
            Edges[id].from = x;
            Edges[id].to = y;
            Edges[id++].w = Dist(Point[x],Point[y]);    //建立有向图
        }
        double ans = ZhuLiu(0,N,id);
        if(ans == -1)   //不能构成最小树形图
            printf("poor snoopy\n");
        else
            printf("%.2lf\n",ans);
    }
    return 0;
}

~~正在更新

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值