hdu2121+不定根最小树形图
算和定根最小树形图相同。
我们只需:设一个权值sumw=所有边之和+1,类似于网络流,向图中加入一个超级源点,把这个点作为虚根。虚根到其他所有点之间连上一条边,边权值为sumw.
求出的值减去sumw即为最小树形图的权值。
当然,返回-1则无解。此外,当求出的值>=2*sumw,也是无解的。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 struct node 5 { 6 int u,v; 7 long long int w; 8 }edge[22000]; 9 int n,m,pre[1100],minroot,sume; 10 long long int in[1100],mmax; 11 long long int solve(int root) 12 { 13 int mark[1100],vis[1100],i; 14 long long int ans=0; 15 while(true) 16 { 17 for(i=0;i<n;i++) 18 in[i]=mmax; 19 for(i=0;i<sume;i++) 20 { 21 int u1=edge[i].u; 22 int v1=edge[i].v; 23 if(edge[i].w<in[v1]&&u1!=v1) 24 { 25 in[v1]=edge[i].w; 26 pre[v1]=u1; 27 if(u1==root) minroot=i; 28 } 29 } 30 for(i=0;i<n;i++) 31 { 32 if(i==root) continue; 33 if(in[i]==mmax) return -1; 34 } 35 int cnt=0; 36 memset(vis,-1,sizeof(vis)); 37 memset(mark,-1,sizeof(mark)); 38 in[root]=0; 39 for(i=0;i<n;i++) 40 { 41 ans+=in[i]; 42 int v=i; 43 while(v!=root&&vis[v]!=i&&mark[v]==-1) 44 { 45 vis[v]=i; 46 v=pre[v]; 47 } 48 if(v!=root&&mark[v]==-1) 49 { 50 int u; 51 for(u=pre[v];u!=v;u=pre[u]) 52 { 53 mark[u]=cnt; 54 } 55 mark[v]=cnt++; 56 } 57 } 58 if(cnt==0) break; 59 for(i=0;i<n;i++) 60 { 61 if(mark[i]==-1) 62 mark[i]=cnt++; 63 } 64 for(i=0;i<sume;i++) 65 { 66 int u2=edge[i].u; 67 int v2=edge[i].v; 68 edge[i].u=mark[u2]; 69 edge[i].v=mark[v2]; 70 if(mark[u2]!=mark[v2]) 71 edge[i].w-=in[v2]; 72 } 73 n=cnt; 74 root=mark[root]; 75 } 76 return ans; 77 } 78 int main() 79 { 80 int i; 81 long long int sum; 82 mmax=999999999999999; 83 while(scanf("%d%d",&n,&m)!=EOF) 84 { 85 sum=0; 86 for(i=0;i<m;i++) 87 { 88 scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w); 89 sum+=edge[i].w; 90 } 91 for(i=m;i<n+m;i++) 92 { 93 edge[i].u=n; 94 edge[i].v=i-m; 95 edge[i].w=sum+1; 96 } 97 sume=n+m; 98 n++; 99 long long int aans=solve(n-1); 100 if(aans==-1||aans>=(2*sum+2)) printf("impossible\n"); 101 else 102 printf("%I64d %d\n",aans-sum-1,minroot-m); 103 printf("\n"); 104 } 105 return 0; 106 }