bzoj2595 [Wc2008]游览计划
Description
Input
第一行有两个整数,N和 M,描述方块的数目。
接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点;
否则表示控制该方块至少需要的志愿者数目。 相邻的整数用 (若干个) 空格隔开,
行首行末也可能有多余的空格。
Output
由 N + 1行组成。第一行为一个整数,表示你所给出的方案
中安排的志愿者总数目。
接下来 N行,每行M 个字符,描述方案中相应方块的情况:
z ‘_’(下划线)表示该方块没有安排志愿者;
z ‘o’(小写英文字母o)表示该方块安排了志愿者;
z ‘x’(小写英文字母x)表示该方块是一个景点;
注:请注意输出格式要求,如果缺少某一行或者某一行的字符数目和要求不
一致(任何一行中,多余的空格都不允许出现) ,都可能导致该测试点不得分。
Sample Input
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0
Sample Output
xoox
___o
___o
xoox
HINT
对于100%的数据,N,M,K≤10,其中K为景点的数目。输入的所有整数均在[0,2^16]的范围内
正解:斯坦纳树。
$thusc$的$day1t1$考了斯坦纳树,但是我没学啊,于是$gg$。。
斯坦纳树大概就是求一个连通图满足某些鬼畜条件的生成树??其实似乎挺简单的样子。。
比如这题,我们要求使得所有关键点连通的最小生成树,那么我们可以把这些关键点状压起来。
设$f[i][j][s]$,表示以点$(i,j)$为根,关键点状态为$s$的最小生成树。
那么,每一层$s$内,我们先枚举$s$的子集,$f[i][j][s]=min(f[i][j][s],f[i][j][sub]+f[i][j][s-sub]-g[i][j])$,$g[i][j]$为当前根的权值。很显然,根算了两次,所以我们要减掉。
子集转移完以后,我们可以用$spfa$来松弛整层,$f[i][j][s]=min(f[i][j][s],f[p][q][s]+dis(i,j,p,q))$。
最后某个关键点的全集状态$f[i][j][S]$就是答案了。。然后这题要输出方案,我们记录前驱,搜索一下状态树就好了。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1<<30) 15 #define all (1<<k) 16 #define il inline 17 #define RG register 18 #define ll long long 19 20 using namespace std; 21 22 const int d1[4]={1,0,-1,0}; 23 const int d2[4]={0,1,0,-1}; 24 25 int pre[12][12][1<<11][3],f[12][12][1<<11],a[12][12],g[12][12],vis[12][12],q1[100010],q2[100010],n,m,k; 26 27 il int gi(){ 28 RG int x=0,q=1; RG char ch=getchar(); 29 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 30 if (ch=='-') q=-1,ch=getchar(); 31 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 32 return q*x; 33 } 34 35 il void dfs(RG int x,RG int y,RG int s){ 36 if (!x || !y) return; a[x][y]=1,dfs(pre[x][y][s][0],pre[x][y][s][1],pre[x][y][s][2]); 37 if (pre[x][y][s][0]==x && pre[x][y][s][1]==y) dfs(x,y,s^pre[x][y][s][2]); return; 38 } 39 40 il void spfa(RG int s){ 41 RG int h=0,t=0; 42 for (RG int i=1;i<=n;++i) 43 for (RG int j=1;j<=m;++j) 44 if (f[i][j][s]!=f[0][0][0]) q1[++t]=i,q2[t]=j,vis[i][j]=1; 45 while (h<t){ 46 RG int x=q1[++h],y=q2[h],nowx,nowy; 47 for (RG int i=0;i<4;++i){ 48 nowx=x+d1[i],nowy=y+d2[i]; 49 if (!nowx || !nowy || nowx>n || nowy>m) continue; 50 if (f[nowx][nowy][s]>f[x][y][s]+g[nowx][nowy]){ 51 f[nowx][nowy][s]=f[x][y][s]+g[nowx][nowy],pre[nowx][nowy][s][0]=x; 52 pre[nowx][nowy][s][1]=y,pre[nowx][nowy][s][2]=s; 53 if (!vis[nowx][nowy]) vis[nowx][nowy]=1,q1[++t]=nowx,q2[t]=nowy; 54 } 55 } 56 vis[x][y]=0; 57 } 58 return; 59 } 60 61 il void work(){ 62 n=gi(),m=gi(),memset(f,0x3f3f3f,sizeof(f)); 63 for (RG int i=1;i<=n;++i) 64 for (RG int j=1;j<=m;++j){ 65 g[i][j]=gi(); 66 if (!g[i][j]) f[i][j][1<<(k++)]=0; 67 } 68 if (!k){ 69 puts("0"); 70 for (RG int i=1;i<=n;++i){ 71 for (RG int j=1;j<=m;++j) printf("_"); puts(""); 72 } 73 return; 74 } 75 for (RG int s=1;s<all;++s){ 76 for (RG int i=1;i<=n;++i) 77 for (RG int j=1;j<=m;++j){ 78 for (RG int sub=(s-1)&s;sub;sub=(sub-1)&s){ 79 if (f[i][j][sub]==f[0][0][0] || f[i][j][s^sub]==f[0][0][0]) continue; 80 RG int now=f[i][j][sub]+f[i][j][s^sub]-g[i][j]; 81 if (f[i][j][s]>now) f[i][j][s]=now,pre[i][j][s][0]=i,pre[i][j][s][1]=j,pre[i][j][s][2]=sub; 82 } 83 } 84 spfa(s); 85 } 86 for (RG int i=1;i<=n;++i) 87 for (RG int j=1;j<=m;++j){ 88 if (g[i][j]) continue; printf("%d\n",f[i][j][all-1]),dfs(i,j,all-1); 89 for (RG int i=1;i<=n;++i){ 90 for (RG int j=1;j<=m;++j) 91 if (!g[i][j]) printf("x"); 92 else if (a[i][j]) printf("o"); 93 else printf("_"); 94 puts(""); 95 } 96 return; 97 } 98 return; 99 } 100 101 int main(){ 102 work(); 103 return 0; 104 }