最小生成树是最小斯坦纳树的一种特殊情况
最小生成树是在给定的点集和边中寻求最短网络使所有点连通
而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小
BZOJ2595
题意是给定一个棋盘图。告诉你景点的位置
然后让你在一些格子上放置指定数量的志愿者使得景点之间可以连通
问你最少需要派遣多少枚志愿者
典型斯坦纳树问题
令f[i][j][k]表示已经连接的景点的集合为k时,包含点a[i][j]的最小值
集合k的引入标志着这是一种状压DP
即以(i,j)为根时,景点集合为k时的斯坦纳树。然后有两种转移
1.由两个子集合并得到集合k,即f[i][j][k]=f[i][j][x]+f[i][j][y]-a[i][j],x|y=k(用景点枚举子集)
2.由根的转移得到,即f[i][j][k]=f[x][y][k]+a[i][j],其中(i,j)和(x,y)相邻(最短路直接SPFA,同层之间的转移有环?)
1 #include<cstdio> 2 #include<queue> 3 //#include<iostream> 4 using namespace std; 5 const int INF=100000000; 6 const int maxn=15; 7 const int maxm=15; 8 int n,m,K; 9 int bin[25]; 10 bool inq[maxn][maxm],vis[maxn][maxm]; 11 int a[maxn][maxm]; 12 int f[maxn][maxm][1024]; 13 int dx[4]={0,0,1,-1}; 14 int dy[4]={1,-1,0,0}; 15 queue<pair<int,int> > q; 16 struct Data 17 { 18 int fit,sed,thd; 19 }pre[maxn][maxm][1024]; 20 inline int read() 21 { 22 int x=0;char ch=getchar(); 23 while(ch>'9'||ch<'0') ch=getchar(); 24 while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} 25 return x; 26 } 27 void spfa(int sta) 28 { 29 //cout<<"###"<<sta<<endl; 30 while(!q.empty()) 31 { 32 int x=q.front().first,y=q.front().second; 33 inq[x][y]=0;q.pop(); 34 //cout<<x<<" "<<y<<endl; 35 for(int k=0;k<4;k++) 36 { 37 int nx=x+dx[k],ny=y+dy[k]; 38 if(x<1||y<1||x>n||y>m) continue; 39 if(f[nx][ny][sta]>f[x][y][sta]+a[nx][ny]) 40 { 41 f[nx][ny][sta]=f[x][y][sta]+a[nx][ny]; 42 pre[nx][ny][sta]=(Data){x,y,sta}; 43 if(!inq[nx][ny]) 44 { 45 q.push(make_pair(nx,ny)); 46 inq[nx][ny]=1; 47 } 48 } 49 } 50 } 51 } 52 void dfs(int x,int y,int sta) 53 { 54 if(x>INF||pre[x][y][sta].thd==0) return; 55 vis[x][y]=1; 56 Data t=pre[x][y][sta]; 57 dfs(t.fit,t.sed,t.thd); 58 if(t.fit==x&&t.sed==y) dfs(x,y,sta-t.thd); 59 } 60 int main() 61 { 62 bin[0]=1; 63 for(int i=1;i<20;i++) bin[i]=bin[i-1]<<1; 64 n=read();m=read(); 65 for(int i=1;i<=n;i++) 66 for(int j=1;j<=m;j++) 67 { 68 a[i][j]=read(); 69 if(a[i][j]==0) K++; 70 } 71 //令f[i][j][k]表示已经连接的景点的集合为k时 72 //包含点a[i][j]的最小值 73 for(int i=1;i<=n;i++) 74 for(int j=1;j<=m;j++) 75 for(int k=0;k<bin[K];k++) 76 f[i][j][k]=pre[i][j][k].fit=INF; 77 K=0; 78 for(int i=1;i<=n;i++) 79 for(int j=1;j<=m;j++) 80 if(a[i][j]==0) 81 f[i][j][bin[K]]=0,K++; 82 //最初始是one-hot,集合中只有自己景点 83 for(int sta=1;sta<bin[K];sta++) 84 { 85 for(int i=1;i<=n;i++) 86 { 87 for(int j=1;j<=m;j++) 88 { 89 for(int s=sta&(sta-1);s;s=sta&(s-1)) 90 { 91 int t=f[i][j][s]+f[i][j][sta-s]-a[i][j]; 92 if(t<f[i][j][sta]) 93 { 94 f[i][j][sta]=t; 95 pre[i][j][sta]=(Data){i,j,s}; 96 } 97 } 98 if(f[i][j][sta]<INF) 99 q.push(make_pair(i,j)),inq[i][j]=1; 100 } 101 } 102 spfa(sta); 103 } 104 int x,y; 105 for(int i=1;i<=n;i++) 106 for(int j=1;j<=m;j++) 107 if(a[i][j]==0) 108 { 109 x=i;y=j;break; 110 } 111 dfs(x,y,bin[K]-1); 112 printf("%d ",f[x][y][bin[K]-1]); 113 for(int i=1;i<=n;i++) 114 { 115 for(int j=1;j<=m;j++) 116 { 117 if(a[i][j]==0) printf("x"); 118 else if(vis[i][j]) printf("o"); 119 else printf("_"); 120 } 121 puts(""); 122 } 123 return 0; 124 }
这个题写完之后有一种莫名的打击感