【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)

2595: [Wc2008]游览计划

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special Judge
Submit: 1572  Solved: 739

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]的范围内

Source

 

【分析】

  又是不会的一题啦~

  斯坦纳树?smg?

  刚开始看题可能觉得是最小生成树吧?但是并不是的。

  

  一个条路径可能在最小生成树上面算几次,但是在这题上只算一次。

  然后就是斯坦纳树??【长姿势??

  反正就是,要覆盖的点很少<=10,可以状压这个,f[i][j][t]表示和(i,j)这个格子联通的需覆盖点集合为t的最小代价。

  两个方程:

  $f[i][j][t]=min(f[i][j][s]+f[i][j][t-ss])$ s是t的子集。

  $f[i][j][t]=min(f[x][y][t]+a[i][j])$ (i,j)与(x,y)相邻

  第二个式子啊不是普通的dp啊,转移状态的有环的!!但是,不怕,肯定是小的转到大的,然后一脸最短路的样子,就可以用spfa解决的。

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define INF 0xfffffff
  9 
 10 int a[15][15],num[15][15],f[15][15][1500];
 11 
 12 struct node {int x,y,d;};
 13 node g[15][15][1500];
 14 queue<node > q;
 15 bool inq[15][15];
 16 
 17 int bx[6]={0,1,0,-1,0},
 18     by[6]={0,0,1,0,-1};
 19 
 20 void dfs(int x,int y,int k)
 21 {
 22     if(!k) return;inq[x][y]=1;
 23     dfs(g[x][y][k].x,g[x][y][k].y,g[x][y][k].d);
 24     if(g[x][y][k].x==x&&g[x][y][k].y==y) dfs(x,y,k-g[x][y][k].d);
 25 }
 26 
 27 int main()
 28 {
 29     int n,m,cnt=0;
 30     scanf("%d%d",&n,&m);
 31     memset(f,63,sizeof(f));
 32     for(int i=1;i<=n;i++)
 33      for(int j=1;j<=m;j++)
 34      {
 35          scanf("%d",&a[i][j]);
 36          if(a[i][j]==0)
 37          {
 38              num[i][j]=++cnt;
 39              f[i][j][1<<cnt-1]=0;
 40              g[i][j][1<<cnt-1].x=g[i][j][1<<cnt-1].y=g[i][j][1<<cnt-1].d=0;
 41          }
 42      }
 43     for(int i=1;i<=n;i++)
 44      for(int j=1;j<=m;j++) f[i][j][0]=0;
 45     for(int k=1;k<=(1<<cnt)-1;k++)
 46     {
 47         memset(inq,0,sizeof(inq));
 48         for(int ss=k;ss;ss=(ss-1)&k)
 49         {
 50             for(int i=1;i<=n;i++)
 51              for(int j=1;j<=m;j++) //if(a[i][j]==0)
 52              {
 53                  if(f[i][j][k]>f[i][j][ss]+f[i][j][k-ss]-a[i][j])
 54                 {
 55                     f[i][j][k]=f[i][j][ss]+f[i][j][k-ss]-a[i][j];
 56                     node nw;
 57                     nw.x=i;nw.y=j;nw.d=ss;
 58                     g[i][j][k]=nw;
 59                 }
 60                 if(f[i][j][k]<INF) {node nw;nw.x=i;nw.y=j;nw.d=f[i][j][k];inq[i][j]=1;q.push(nw);}
 61              }
 62             
 63         }
 64         while(!q.empty())
 65         {
 66             node x=q.front();
 67             for(int i=1;i<=4;i++)
 68             {
 69                 int nx=x.x+bx[i],ny=x.y+by[i];
 70                 if(nx<1||nx>n||ny<1||ny>m) continue;
 71                 if(f[nx][ny][k]>f[x.x][x.y][k]+a[nx][ny])
 72                 {
 73                     f[nx][ny][k]=f[x.x][x.y][k]+a[nx][ny];
 74                     node nw;
 75                     nw.x=nx;nw.y=ny;//nw.d=f[nx][ny][k];
 76                     // g[nx][ny][k]=g[x.x][x.y][k];
 77                     g[nx][ny][k].x=x.x;g[nx][ny][k].y=x.y;g[nx][ny][k].d=k;
 78                     if(!inq[nx][ny])
 79                     {
 80                         inq[nx][ny]=1;
 81                         q.push(nw);
 82                     }
 83                 }
 84             }
 85             q.pop();inq[x.x][x.y]=0;
 86         }
 87     }
 88     memset(inq,0,sizeof(inq));
 89     bool ok=0;
 90     for(int i=1;i<=n;i++)
 91     {
 92         for(int j=1;j<=m;j++) if(a[i][j]==0)
 93         {
 94             printf("%d\n",f[i][j][(1<<cnt)-1]);
 95             dfs(i,j,(1<<cnt)-1);
 96             ok=1;break;
 97         }
 98         if(ok) break;
 99     }
100      
101     for(int i=1;i<=n;i++)
102     {
103         for(int j=1;j<=m;j++)
104         {
105             if(a[i][j]==0) printf("x");
106             else if(inq[i][j]) printf("o");
107             else printf("_");
108         }
109         printf("\n");
110     }
111     return 0;
112 }
View Code

 

2017-04-05 19:28:31

posted @ 2017-04-05 19:28  konjak魔芋  阅读(131)  评论(0编辑  收藏  举报