最小树形图

关于最小树形图, 看了下资料和研究了一下代码 。

熟悉了最小树形图的结构还有朱刘算法的大概过程。

最小树形图 跟 最小生成树有两点不同之处: 一有向 、二有根 。

简而言之 , 是能够从根到达各个节点 , 所构成的有向图 , 要求边权之和最小 。

对于朱刘算法 ,有4个步骤 。

1.判断是否存在最小树形图 。

2.对图进行标记,判环,无环则可返回。

2.将图中的环缩成点。

3.构成新图。

对于标记缩点的时候 ,朝着pre[u]走要么就是回溯到root , 要么就是构成了环。

在构新图的时候 , 若然e[i].u , e[i].v在环里 , 可以直接扔掉 , 因为在操作2的时候,整个环的权值已经加过了 。

当有点进入环的时候 , 比如进入环中一点 v , 其权要减回一个in[v] ( 表示上一次构图指向v的边的最小权 , 在上一次步骤2的时候多加到了结果中 )。

double zhuliu( int root ) {
    double res = 0 ; int u , v ;
    while(1) {
        for( int i = 0 ; i < n ; ++i ) in[i] = inf ;

        for( int i = 0 ; i < m ; ++i )
            if( e[i].u != e[i].v && e[i].w < in[e[i].v] ) {
                pre[e[i].v] = e[i].u;
                in[e[i].v] = e[i].w;
            }
        for( int i = 0 ; i < n ; ++i )
            if( i != root && in[i] == inf )
                return -1 ;
        int tn = 0 ;
        memset( id , -1 , sizeof id );
        memset( vis , -1 , sizeof vis );
        in[root] = 0 ;
        for( int i = 0 ; i < n ; ++i ) {
            res += in[i];
            v = i ;
            while( vis[v] != i && id[v] == -1 && v != root ) {
                vis[v] = i ;
                v = pre[v] ;
            }
            if( v != root && id[v] == -1 ) {
                for( int u = pre[v] ; u != v ; u = pre[u] )
                    id[u] = tn ;
                id[v] = tn++ ;
            }
        }
        if( tn == 0 ) break ; // no circle
        for( int i = 0 ; i < n ; ++i ) if( id[i] == -1 ) {
            id[i] = tn++ ;
        }
        for( int i = 0 ; i < m ; ){
            v = e[i].v;
            e[i].u = id[e[i].u];
            e[i].v = id[e[i].v];
            if( e[i].u != e[i].v )
                e[i++].w -= in[v];
            else
                swap( e[i] , e[--m] );
        }
        n = tn ;
        root = id[root];
    }
    return res ;
}
View Code
only strive for your goal , can you make your dream come true ?
原文地址:https://www.cnblogs.com/hlmark/p/4292078.html