首页 > 代码库 > Directed_MST 最小树形图

Directed_MST 最小树形图

 


List

 

  • Directed_MST 最小树形图
    • List
    • Knowledge
    • 模板
    • Practice
    • 参考资料

 

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;

 

Practice

Bzoj1179 Apio2009 Atm(2016-09-20 19:54)

参考资料

Wiki Minimum spanning tree 
Wiki Edmonds’ algorithm

Directed_MST 最小树形图