bzoj2595 [Wc2008]游览计划
Input
第一行有两个整数,N和 M,描述方块的数目。
接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点;
否则表示控制该方块至少需要的志愿者数目。 相邻的整数用 (若干个) 空格隔开,
行首行末也可能有多余的空格。
Output
由 N + 1行组成。第一行为一个整数,表示你所给出的方案
中安排的志愿者总数目。
接下来 N行,每行M 个字符,描述方案中相应方块的情况:
z ‘_’(下划线)表示该方块没有安排志愿者;
z ‘o’(小写英文字母o)表示该方块安排了志愿者;
z ‘x’(小写英文字母x)表示该方块是一个景点;
注:请注意输出格式要求,如果缺少某一行或者某一行的字符数目和要求不
一致(任何一行中,多余的空格都不允许出现) ,都可能导致该测试点不得分。
Sample Input
4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0
Sample Output
6
xoox
___o
___o
xoox
xoox
___o
___o
xoox
HINT
对于100%的数据,N,M,K≤10,其中K为景点的数目。输入的所有整数均在[0,2^16]的范围内
思路: 本题是最小斯坦纳树的模板题,难点在于需要记录方案。
令f[i][j][k]表示已经连接的景点的集合为k时,包含点a[i][j]的最小值。即以(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)相邻。
最小斯坦纳树有多种转移方法,要注意区分,这里是按照相同状态转移和子状态转移两种情况来考虑,相同状态转移就需要用到最短路径算法了,注意f[i][j][k]里面i,j这个位置并不一定体现在k这个二进制里面,这也是我之前一直有点疑惑的原因。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int const inf=1e9; 4 int const N=12; 5 int const M=1105; 6 int n,m,a[N][N],f[N][N][M],pre[N][N][M][3],h[M+5][2],p; 7 bool bo[N][N]; 8 int dx[4]={0,0,1,-1}; 9 int dy[4]={1,-1,0,0}; 10 void dfs(int x,int y,int k){ 11 if(!k) return; 12 bo[x][y]=1; 13 dfs(pre[x][y][k][0],pre[x][y][k][1],pre[x][y][k][2]); 14 if(pre[x][y][k][0]==x && pre[x][y][k][1]==y) 15 dfs(x,y,k^pre[x][y][k][2]); 16 } 17 void work(int x,int y){ 18 printf("%d\n",f[x][y][(1<<p)-1]); 19 memset(bo,0,sizeof(bo)); 20 dfs(x,y,(1<<p)-1); 21 for(int i=1;i<=m;i++){ 22 for(int j=1;j<=n;j++) 23 if(a[i][j]) putchar(bo[i][j]? 'o':'_'); 24 else putchar('x'); 25 printf("\n"); 26 } 27 } 28 29 int main(){ 30 scanf("%d%d",&m,&n); 31 int k,x,y; 32 for(int i=1;i<=m;i++) 33 for(int j=1;j<=n;j++) 34 for(int k=0;k<(1<<10);k++) f[i][j][k]=inf; 35 for(int i=1;i<=m;i++) 36 for(int j=1;j<=n;j++) { 37 scanf("%d",&a[i][j]); 38 if(a[i][j]==0) 39 f[i][j][1<<p]=0,p++; 40 } 41 for(int k=1;k<(1<<p);k++){ 42 int l=0,r=0; 43 memset(bo,1,sizeof(bo)); 44 for(int i=1;i<=m;i++) for(int j=1;j<=n;j++){ 45 for(int x=k&(k-1);x;x=(x-1)&k){ 46 int tmp=f[i][j][x]+f[i][j][k^x]-a[i][j]; 47 if(tmp<f[i][j][k]){ 48 f[i][j][k]=tmp; 49 pre[i][j][k][0]=i; 50 pre[i][j][k][1]=j; 51 pre[i][j][k][2]=x; 52 } 53 } 54 if(f[i][j][k]<inf){ 55 h[++r][0]=i; 56 h[r][1]=j; 57 bo[i][j]=0; 58 } 59 } 60 while (l!=r){ 61 l=l%M+1; 62 x=h[l][0]; y=h[l][1]; bo[x][y]=1; 63 for(int i=0;i<4;i++){ 64 int u=x+dx[i]; 65 int v=y+dy[i]; 66 if(u<1 || u>m || v<1 || v>n) continue; 67 if(f[x][y][k]+a[u][v]<f[u][v][k]){ 68 f[u][v][k]=f[x][y][k]+a[u][v]; 69 pre[u][v][k][0]=x; 70 pre[u][v][k][1]=y; 71 pre[u][v][k][2]=k; 72 if(bo[u][v]){ 73 bo[u][v]=0; r=r%M+1; 74 h[r][0]=u;h[r][1]=v; 75 } 76 } 77 } 78 } 79 } 80 for(int i=1;i<=m;i++) 81 for(int j=1;j<=n;j++) 82 if(a[i][j]==0){ 83 work(i,j); 84 return 0; 85 } 86 return 0; 87 } 88