hdu 2121

朱刘算法求无根最小树形图

可以任意选一个根,求最小的权和以及当时的根。

先建一个超级根,它连向所有点,边权为所有边的边权和加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 }
View Code
原文地址:https://www.cnblogs.com/idy002/p/4450917.html