最小树形图--朱刘算法

描述:最小树形图—-一个有向图的有根生成树中权最小的图。
原理:朱刘算法及相关定理。
代码

#include<bits\stdc++.h> 
using namespace std; 

typedef int CostType;

struct Edge{
    int u;
    int v;
    CostType cost;
    Edge(){};
    Edge(int x,int y,CostType c):u(x),v(y),cost(c){};

};

#define MV 1005
#define ME 100005
#define Max INT_MAX

CostType liu_zhu(Edge* E,int vn,int em,int root){
    /*  该算法求一个图G的最小树形图。
        E是图中边的集合。
        vn是图中点的个数,编号依次为0,1,2……n-1。
        em为边集E的大小。
        root为指定的根。
    */
    /*
        算法包括几个部分:求最小入弧集,找孤立点,找圈,缩点。
    */
    CostType min_in[vn];//记录最小入弧的大小。
    int pre[vn];//记录最小入弧的关联点。
    int vis[vn];//找圈时记录被那个点访问过。
    int new_id[vn];//缩点时新的编号。
    int min_cost=0;//返回结果。
    memset(min_in,Max,vn);
    memset(pre,-1,vn);
    while(true){
        for(int i=0;i<em;i++)//找最小入弧集,排除自环。
        if(E[i].u!=E[i].v&&E[i].cost<min_in[E[i].v]){
            min_in[E[i].v]=E[i].cost;
            pre[E[i].v]=E[i].u;
        }
        int now_new_id=0;
        for(int i=0;i<vn;i++)//找孤立点.
        if(i!=root&&pre[i]==-1)
            return -1;
        memset(vis,-1,vn);
        memset(new_id,-1,vn);
        min_in[root]=0;
        for(int i=0;i<vn;i++){
            min_cost+=min_in[i];
            /*  最小树形图除顶点外一定每一点都有一条入弧,将最小值加入结果。
                然后重新编号时将所有入弧都减去最小值。
            */
            int v;
            for(v=i;v!=root&&vis[v]!=i&&new_id[v]==-1;v=pre[v]){
                /*在最小弧集中找圈。从i点开始往前找,直到找到根(无圈),
                    或者找到一个之前访问过的点(即一个圈)。
                */
                vis[v]=i;
            }
            if(v!=root&&new_id[v]==-1){
                //有一个新圈,将圈中元素编号。
                for(int u=v;new_id[u]==-1;u=pre[u])
                    new_id[u]=now_new_id;
                now_new_id++;
            }
        }
        if(now_new_id==0) break;//若没有圈,结束。
        for(int i=0;i<vn;i++)//对圈外其他点赋予新编号。
            if(new_id[i]==-1)
                new_id[i]=now_new_id++;

        for(int i=0;i<em;i++){
            /*更新编号,同时,更新权。最后,所有边权为的边构成最小树形图。
                有可能某些点有多条权为0的边,保留其中一条不改变连通性的边即可。
            */
            int v=E[i].v;
            E[i].v=new_id[E[i].v];
            E[i].u=new_id[E[i].u];
            E[i].cost-=min_in[v];
        }
        vn=now_new_id;
        root=new_id[root];//最后,更新节点数和根节点编号。
    }
    return min_cost;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值