关于最小树形图, 看了下资料和研究了一下代码 。
熟悉了最小树形图的结构还有朱刘算法的大概过程。
最小树形图 跟 最小生成树有两点不同之处: 一有向 、二有根 。
简而言之 , 是能够从根到达各个节点 , 所构成的有向图 , 要求边权之和最小 。
对于朱刘算法 ,有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 ; }