[bzoj2595][斯坦纳树]游览计划

版权声明:蒻蒟的bolg... https://blog.csdn.net/Rose_max/article/details/85242674

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

题解

偷学了一下斯坦纳树
大概就是解决这样一个问题
给定一个集合,要求把这个集合里面的点连起来并且代价最小,可以引入集合外的点
可以设 f [ x ] [ y ] [ m a s k ] f[x][y][mask] 表示位置在 ( x , y ) (x,y) 的点为根,与给定集合点连接状态为 m a s k mask 的最小权
两种转移
f [ x ] [ y ] [ m a s k ] = m i n ( f [ x ] [ y ] [ s u b m a s k ] + f [ x ] [ y ] [ m a s k s u b m a s k ] v a l [ x ] [ y ] ) f[x][y][mask]=min(f[x][y][submask]+f[x][y][mask^submask]-val[x][y])
就是枚举它的两个大型子树(子集)
另一种就是
f [ x ] [ y ] [ m a s k ] = m i n ( f [ x ] [ y ] [ m a s k ] + v a l [ x ] [ y ] ) f[x][y][mask]=min(f[x'][y'][mask]+val[x][y])
其中 ( x , y ) ( x , y ) (x',y')与(x,y) 相连
容易发现第二种可以用spfa转移
第一种直接转移
然后就是个裸的了…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(int x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=11;
const int MAXMASK=(1<<10)+5;
const int dx[4]={0,-1,0,1};
const int dy[4]={-1,0,1,0};
int bin[25];
int f[MAXN][MAXN][MAXMASK],n,m,tot;
int val[MAXN][MAXN];
int pt(int x,int y){return (x-1)*m+y;}
bool in(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}

queue<pii> li;
bool vis[MAXN][MAXN];
struct pre
{
	int x,y,ok1,ok2;
	pre(){}
	pre(int _x,int _y,int _ok1,int _ok2){x=_x;y=_y;ok1=_ok1;ok2=_ok2;}
}P[MAXN][MAXN][MAXMASK];
void spfa(int S)
{
	while(!li.empty())
	{
		int x=li.front().first,y=li.front().second;
		vis[x][y]=false;li.pop();
		for(int k=0;k<=3;k++)
		{
			int u=x+dx[k],v=y+dy[k];
			if(in(u,v)&&f[u][v][S]>f[x][y][S]+val[u][v])
			{
				f[u][v][S]=f[x][y][S]+val[u][v];
				P[u][v][S]=pre(x,y,0,0);
				if(!vis[u][v])vis[u][v]=true,li.push(mp(u,v));
			}
		}
	}
}

void dfs(int x,int y,int mask)
{
	if(!mask)return ;
	if(val[x][y])val[x][y]=-1;
	if(P[x][y][mask].x)dfs(P[x][y][mask].x,P[x][y][mask].y,mask);
	else 
	{
		dfs(x,y,P[x][y][mask].ok1);
		dfs(x,y,P[x][y][mask].ok2);
	}
}
int main()
{
	bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
	n=read();m=read();
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)val[i][j]=read();
	
	memset(f,63,sizeof(f));
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(!val[i][j])
	{
		f[i][j][bin[tot]]=0;
		tot++;
	}
	tot--;
	for(int mask=1;mask<bin[tot+1];mask++)
	{
		for(int x=1;x<=n;x++)
			for(int y=1;y<=m;y++)
			{
				for(int nxt=(mask-1)&mask;nxt;nxt=(nxt-1)&mask)
					if(f[x][y][nxt]+f[x][y][mask^nxt]-val[x][y]<f[x][y][mask])
					{
						f[x][y][mask]=f[x][y][nxt]+f[x][y][mask^nxt]-val[x][y];
						P[x][y][mask]=pre(0,0,nxt,mask^nxt);
					}
				if(f[x][y][mask]<1e9)li.push(mp(x,y)),vis[x][y]=true;
			}
		spfa(mask);
	}
	
	int ans=(1<<31-1);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
		ans=min(ans,f[i][j][bin[tot+1]-1]);
	pr2(ans);bool tf=false;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)if(ans==f[i][j][bin[tot+1]-1])
		{
			dfs(i,j,bin[tot+1]-1);
			tf=true;break;
		}
		if(tf)break;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(!val[i][j])putchar('x');
			else if(val[i][j]==-1)putchar('o');
			else putchar('_');
		}
		puts("");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/85242674
今日推荐