朱刘算法求无根最小树形图
可以任意选一个根,求最小的权和以及当时的根。
先建一个超级根,它连向所有点,边权为所有边的边权和加1(即sumw+1),然后求以它为根的最小树形图,再根据树形图权和与2*(sumw+1)的关系判断是否存在解(如果大于等于就不存在,否则存在)。
至于求对应的原图中的根,我们发现自始自终,超级根都不可能在一个环中,并且在最有一个状态,一定是一个没有环的树形图,该图中与前趋为超级根的点,就是原图中的根所在的环缩成的点,怎么得到具体是哪一个点呢,我们可以记下那条边在最开始指向的是哪个点,那个点就是原图中的根(可以根据缩点的正确性证明它的正确性)。
1 #include <cstdio> 2 #define oo 0x7FFFFFFF 3 #define N 1010 4 #define M 11010 5 6 struct Edge { 7 int u, v, w; 8 int sv; 9 Edge(){} 10 Edge( int u, int v, int w ):u(u),v(v),w(w),sv(v){} 11 }; 12 13 int n, m; 14 int inw[N], inc[N], pre[N], idx[N], vis[N], rsv; 15 Edge edge[M]; 16 17 int directed_mst( int root ) { 18 int rt = 0; 19 while(1) { 20 // inw pre 21 for( int i=1; i<=n; i++ ) 22 inw[i] = oo; 23 for( int i=1; i<=m; i++ ) { 24 Edge &e = edge[i]; 25 if( inw[e.v]>e.w ) { 26 inw[e.v]=e.w; 27 pre[e.v]=e.u; 28 if( e.u==root ) rsv=e.sv; 29 } 30 } 31 // inc idx 32 int cnt = 0; 33 for( int i=1; i<=n; i++ ) 34 idx[i] = vis[i] = 0; 35 for( int i=1,u,v; i<=n; i++ ) { 36 if( i==root ) continue; 37 for( u=pre[i]; u!=root && !idx[u] && vis[u]!=i; u=pre[u] ) 38 vis[u]=i; 39 if( u==root || idx[u] ) continue; 40 cnt++; 41 for( v=pre[u]; v!=u; v=pre[v] ) { 42 idx[v] = cnt; 43 inc[v] = true; 44 rt += inw[v]; 45 } 46 idx[u] = cnt; 47 inc[u] = true; 48 rt += inw[u]; 49 } 50 if( cnt==0 ) { 51 for( int i=1; i<=n; i++ ) 52 if( i!=root ) 53 rt += inw[i]; 54 break; 55 } else { 56 for( int i=1; i<=n; i++ ) 57 if( !idx[i] ) { 58 idx[i] = ++cnt; 59 inc[i] = false; 60 } 61 } 62 // edge 63 int j=0; 64 for( int i=1; i<=m; i++ ) { 65 Edge &e = edge[i]; 66 if( inc[e.v] ) e.w-=inw[e.v]; 67 e.u = idx[e.u]; 68 e.v = idx[e.v]; 69 if( e.u!=e.v ) edge[++j]=edge[i]; 70 } 71 root = idx[root]; 72 n = cnt; 73 m = j; 74 } 75 return rt; 76 } 77 78 int main() { 79 while( scanf("%d%d",&n,&m)==2 ) { 80 int mm=0, sw=0; 81 for( int i=1,u,v,w; i<=m; i++ ) { 82 scanf( "%d%d%d", &u, &v, &w ); 83 if( u==v ) continue; 84 u++, v++; 85 edge[++mm] = Edge(u,v,w); 86 sw+=w; 87 } 88 for( int i=1; i<=n; i++ ) 89 edge[++mm] = Edge(n+1,i,sw+1); 90 m = mm; 91 n = n+1; 92 int ans = directed_mst(n)-sw-1; 93 if( ans>=sw+1 ) printf( "impossible " ); 94 else printf( "%d %d ", ans, rsv-1 ); 95 printf( " " ); 96 } 97 }