2019.03.26【WC2008】【洛谷P4294】【BZOJ2595】游览计划(斯坦纳树)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88821900

洛谷传送门

BZOJ传送门


解析:

很裸的斯坦纳树,细节也不是很多,注意拼凑的时候要减去根节点的重复贡献。

为了输出方案,只需要记录一下 D P DP 转移的方向就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
	}
	
	inline int getint(){
		re char c;
		re bool f=0;
		while(!isdigit(c=gc()))f^=c=='-';re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return f?-num:num;
	}
}
using namespace IO;

using std::cout;
using std::swap;

cs int N=20;
int n,m,p,ex,ey;

cs int INF=1e9;
int f[1<<11][N][N];
int val[N][N];

struct Pre{
	int x,y,s;
	Pre(){}
	Pre(cs int &_x,cs int &_y,cs int &_s):x(_x),y(_y),s(_s){}
}pre[1<<11][N][N];

struct Pos{int x,y;Pos(cs int &_x,cs int &_y):x(_x),y(_y){}};

cs int dx[4]={0,1,0,-1};
cs int dy[4]={1,0,-1,0};
std::queue<Pos,std::list<Pos> > q;
bool in[N][N];
inline void SPFA(int S){
	while(!q.empty()){
		int x=q.front().x,y=q.front().y;q.pop();
		in[x][y]=false;
		for(int re i=0;i<4;++i){
			int nx=x+dx[i],ny=y+dy[i];
			if(nx<1||nx>n||ny<1||ny>m)continue;
			if(f[S][nx][ny]>f[S][x][y]+val[nx][ny]){
				f[S][nx][ny]=f[S][x][y]+val[nx][ny];
				if(!in[nx][ny])q.push(Pos(nx,ny)),in[nx][ny]=true;
				pre[S][nx][ny]=Pre(x,y,S);
			}
		}
	}
}

bool set[N][N];
void dfs(int x,int y,int S){
	if(!pre[S][x][y].s)return ;
	set[x][y]=true;
	Pre &p=pre[S][x][y];
	dfs(p.x,p.y,p.s);
	if(p.x==x&&p.y==y)dfs(x,y,S^p.s); 
}

signed main(){
	memset(f,0x3f,sizeof f);
	n=getint(),m=getint();
	for(int re i=1;i<=n;++i)
	for(int re j=1;j<=m;++j){
		val[i][j]=getint();
		if(!val[i][j]){
			f[1<<p][i][j]=0;++p;
			ex=i,ey=j;
		}
	}
	for(int re s=1;s<(1<<p);++s){
		for(int re i=1;i<=n;++i)
		for(int re j=1;j<=m;++j){
			for(int re k=s&(s-1);k;k=s&(k-1))
			if(f[s][i][j]>f[k][i][j]+f[s^k][i][j]-val[i][j]){
				f[s][i][j]=f[k][i][j]+f[s^k][i][j]-val[i][j];
				pre[s][i][j]=Pre(i,j,k);
			}
			if(f[s][i][j]<INF)q.push(Pos(i,j)),in[i][j]=true;
		}
		SPFA(s);
	}
	std::ios::sync_with_stdio(false);
	cout<<f[(1<<p)-1][ex][ey]<<"\n";
	dfs(ex,ey,(1<<p)-1);
	for(int re i=1;i<=n;++i,cout<<"\n")
	for(int re j=1;j<=m;++j)
	if(!val[i][j])cout<<"x";
	else if(set[i][j])cout<<"o";
	else cout<<"_"; 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/88821900