bzoj2595 [Wc2008]游览计划

Description

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

Sample Output

6
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
",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 }
原文地址:https://www.cnblogs.com/wfj2048/p/6918277.html