[WC2008]游览计划(斯坦纳树+输出方案)

空扰寡人 提交于 2020-03-06 03:28:53

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

 

 

 

 

 

题解

显然斯坦纳树(好像也可以插头DP)

怎么输出方案呢?

记录一下每个点是从哪个点转移过来的即可

最后输出方案的时候用一个dfs,怎么转移过来的,就怎么dfs回去

(WA了一次是因为输出了大写的X,一定要小心大小写)

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 15
const int INF=0x3f3f3f3f;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
struct node{
	int x,y,s;
	node(){}
	node(int a,int b,int c){x=a;y=b;s=c;}
}u,v;
int f[N][N][1<<10];
node pre[N][N][1<<10],pos[N];
int a[N][N],ans[N][N];
queue<node> q;bool inq[N][N];
void dfs(node i)
{
	if(!i.x)return;
	ans[i.x][i.y]=1;
	node j=pre[i.x][i.y][i.s];
	dfs(j);
	if(i.x==j.x&&i.y==j.y)dfs(node(i.x,i.y,i.s^j.s));
}
int main()
{
	int n,m,k=0,i,j,s,t,l;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
			if(!a[i][j]){k++;pos[k]=node(i,j,0);}
		}
	}
	memset(f,0x3f,sizeof(f));
	int all=(1<<k)-1;
	for(i=1;i<=n;i++)for(j=1;j<=m;j++)f[i][j][0]=0;
	for(i=1;i<=k;i++)f[pos[i].x][pos[i].y][1<<(i-1)]=0;
	for(s=1;s<=all;s++){
		for(i=1;i<=n;i++)for(j=1;j<=m;j++)
			for(t=(s-1)&s;t;t=(t-1)&s){
				if(f[i][j][s]>f[i][j][t]+f[i][j][s^t]-a[i][j]){
					f[i][j][s]=f[i][j][t]+f[i][j][s^t]-a[i][j];
					pre[i][j][s]=node(i,j,t);
				}
			}
		for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(f[i][j][s]<INF)
			q.push(node(i,j,s)),inq[i][j]=1;
		while(!q.empty()){
			u=q.front();q.pop();inq[u.x][u.y]=0;
			for(l=0;l<4;l++){
				v.x=u.x+dx[l];v.y=u.y+dy[l];v.s=u.s;
				if(v.x>0&&v.x<=n&&v.y>0&&v.y<=m){
					if(f[v.x][v.y][s]>f[u.x][u.y][s]+a[v.x][v.y]){
						f[v.x][v.y][s]=f[u.x][u.y][s]+a[v.x][v.y];
						pre[v.x][v.y][s]=u;
						if(!inq[v.x][v.y])q.push(v),inq[v.x][v.y]=1;
					}
				}
			}
		}
	}
	int mi=INF;node ss;
	for(i=1;i<=n;i++)for(j=1;j<=m;j++)
		if(f[i][j][all]<=mi){
			mi=f[i][j][all];
			ss=node(i,j,all);
		}
	printf("%d\n",mi);
	dfs(ss);
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			if(!a[i][j])printf("x");
			else if(ans[i][j])printf("o");
			else printf("_");
		}
		printf("\n");
	}
}

 

 

 

 

 

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!