码迷,mamicode.com
首页 > 其他好文 > 详细

Directed_MST 最小树形图

时间:2016-10-01 00:01:29      阅读:317      评论:0      收藏:0      [点我收藏+]

标签:

 


Knowledge

求一个图中遍历到每个点的方案中的最小边权和,显然n-1条边,即一颗树即可。 最小生成树?当然这里不是的,这里的最小树形图算法是针对有向图的。 最小树形图的第一个算法是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法。简称朱刘算法。 

1986年, Gabow, Galil, Spencer和Tarjan提出了一个复杂度更好的实现,其时间复杂度为O(E+VlogV)。%啊,又是Tarjan大爷。好像并没有翻到详细的记载,一般用不到。应该有点复杂吧。 

下面介绍一下ZLEdmonds: 

技术分享 
简述:记pre[i]为连到i点所有前驱中边权最小的一个 可以理解如果没有环,那么这个方案即为所求 如果有环肯定就有bug,因为点显然不连通 找环,先默认环上的边都加入答案(后面重构边权会导致最后方案把环上一条边去掉) 缩点将其与其它点连边边权改为w-=w[i→pre[i]],这样最后答案如果连了这条边,环上的点就不要再来一次。 这样缩环后重新找pre,直到不存在环 这样重新构图后,虽然开始有环,但重构的边权会使最后删掉环上的某条边 保证了最后肯定是一个树形图,而且还是最小的

模板

struct Directed_MST{
    static const int N=110,M=N*N;
    static const int/double INF=1e9;
    int m,n,root;
    int/double w[M],s[N],ans;
    int u[M],v[M],pre[N],id[N],f[N];
    void Combine(){
        for(int i=1;i<=m;i++){
            int gg=v[i];u[i]=id[u[i]];v[i]=id[v[i]];
            if(u[i]!=v[i])w[i]-=s[gg];
        }
    }
    void ZLEdmonds(){
        ans=0;
        while(true){
            for(int i=1;i<=n;i++)s[i]=INF;
            for(int i=1;i<=m;i++)
                if(w[i]<s[v[i]]&&u[i]!=v[i])s[v[i]]=w[i],pre[v[i]]=u[i];
            int cnt=1;
            memset(id,-1,sizeof(id));
            memset(f,0,sizeof(f));
            s[root]=0;
            for(int i=1;i<=n;i++){
                ans+=s[i];int x=i;
                while(f[x]!=i&&x!=root)f[x]=i,x=pre[x];
                if(x!=root&&id[x]==-1){
                    for(int o=pre[x];o!=x;o=pre[o])id[o]=cnt;
                    id[x]=cnt++;
                }
            }
            if(cnt==1)break;
            for(int i=1;i<=n;i++)if(id[i]==-1)id[i]=cnt++;
            Combine();n=cnt-1;root=id[root];
        }
        cout<<ans;
    }
}ZL;

 

Directed_MST 最小树形图

标签:

原文地址:http://www.cnblogs.com/YJinpeng/p/5924905.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!