HDU 4085 Peach Blossom Spring
斯坦纳树。
最后可以是森林,在计算出每个联通状态的最小费用后,还需要进行一次$dp$。
#include<bits/stdc++.h> using namespace std; const int INF=0x7FFFFFFF; int T,n,m,k; vector<int>g[60]; int val[60][60],id[60],d[60][1200],dp[1200]; int f[60*10000]; queue<int>Q; void spfa() { while(!Q.empty()) { int h = Q.front(); Q.pop(); f[h]=0; int x=h/10000,y=h%10000; for(int i=0;i<g[x].size();i++) { int to = g[x][i]; if(to<2*k) { if(((1<<to)&y)==0) { if(d[x][y]+val[x][to]<d[to][y|(1<<to)]) d[to][y|(1<<to)]=d[x][y]+val[x][to]; } } else { if(d[x][y]+val[x][to]<d[to][y]) { d[to][y] = d[x][y]+val[x][to]; if(f[to*10000+y]==0) { f[to*10000+y]=1; Q.push(to*10000+y); } } } } } } bool check(int x) { int sum1=0,sum2=0; for(int i=0;i<=k-1;i++) if(x&(1<<i)) sum1++; for(int i=k;i<=2*k-1;i++) if(x&(1<<i)) sum2++; if(sum1==sum2) return 1; return 0; } int main() { scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); for(int i=0;i<n;i++) { id[i]=i; g[i].clear(); } id[k]=n-k; for(int i=k+1;i<=2*k-1;i++) id[i]=id[i-1]+1; id[n-k]=k; for(int i=n-k+1;i<=n-1;i++) id[i]=id[i-1]+1; for(int i=0;i<n;i++) for(int j=0;j<n;j++) val[i][j]=INF; memset(f,0,sizeof f); for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); a--; b--; a=id[a]; b=id[b]; val[a][b]=min(val[a][b],c); val[b][a]=val[a][b]; g[a].push_back(b); g[b].push_back(a); } int st = 1<<(2*k); for(int j=0;j<st;j++) for(int i=0;i<n;i++) d[i][j]=INF; for(int i=0;i<n;i++) { if(i<2*k) d[i][1<<i]=0; else d[i][0]=0; } for(int j=0;j<st;j++) { for(int i=0;i<n;i++) { if(i<2*k) { if(((1<<i)&j)==0) continue; for (int x = j; x; x = (x-1)&j) { int A=x ,B=j-A; if(d[i][A|(1<<i)]!=INF&&d[i][B|(1<<i)]!=INF) d[i][j] = min(d[i][j], d[i][A|(1<<i)]+d[i][B|(1<<i)]); } } else { for (int x = j; x; x = (x-1)&j) { int A=x ,B=j-A; if(d[i][A]!=INF&&d[i][B]!=INF) d[i][j] = min(d[i][j], d[i][A]+d[i][B]); } } if(d[i][j]!=INF) Q.push(i*10000+j); } spfa(); } for(int j=0;j<st;j++) { dp[j]=INF; for(int i=0;i<n;i++) dp[j]=min(dp[j],d[i][j]); } for(int j=0;j<st;j++) { for (int x = j; x; x = (x-1)&j) { int A=x ,B=j-A; if(check(A)&&check(B)&&dp[A]!=INF&&dp[B]!=INF) dp[j]=min(dp[j],dp[A]+dp[B]); } } if(dp[st-1]!=INF) printf("%d\n",dp[st-1]); else printf("No solution\n"); } return 0; }