【BZOJ】【P2595】【Wc2008】【游览计划】【题解】【斯坦纳树】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2595

推荐看姜碧野的《SPFA的优化与应用》以及 http://www.cnblogs.com/lazycal/archive/2013/08/31/bzoj-2595.html

等学会了插头dp再换个姿势写一个

Code:

#include<bits/stdc++.h>
#define fst first
#define sec second
using namespace std;
int n,m,K,inf=100000;
int a[10][10],f[10][10][1<<10];
struct tup{
	int first,second,thd;
	tup(int _fst=0,int _sec=0,int _thd=0):
		first(_fst),second(_sec),thd(_thd){}
}pre[10][10][1<<10],zero;
typedef pair<int,int> par;
queue<par>q;
int vis[10][10];
void spfa(int sta){	
	const static int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
	while(!q.empty()){
		par u=q.front();q.pop();vis[u.fst][u.sec]=0;
		for(int k=0;k<4;k++){
			int x=dx[k]+u.fst,y=dy[k]+u.sec;
			if(x<0||y<0||x>=n||y>=m)continue;
			if(f[x][y][sta]>f[u.fst][u.sec][sta]+a[x][y]){
				f[x][y][sta]=f[u.fst][u.sec][sta]+a[x][y];
				pre[x][y][sta]=tup(u.fst,u.sec,sta);
				if(!vis[x][y])q.push(par(x,y)),vis[x][y]=1;
			}	
		}
	}
}
void dfs(int i,int j,int sta){
	if(i==inf||pre[i][j][sta].thd==0)return;
	vis[i][j]=1;tup tp=pre[i][j][sta];
	dfs(tp.fst,tp.sec,tp.thd);
	if(tp.fst==i&&tp.sec==j)dfs(i,j,sta-tp.thd);
}
int main(){
	cin>>n>>m;
	fill(&f[0][0][0],&f[10][10][1<<10],inf);
	for(int i=0;i<n;i++)
	for(int j=0;j<m;j++){
		cin>>a[i][j];
		if(!a[i][j]){f[i][j][1<<(K++)]=0;}
	}
	for(int sta=1;sta<(1<<K);sta++){
		for(int i=0;i<n;i++)for(int j=0;j<m;j++){
			for(int s=sta&(sta-1);s;s=sta&(s-1)){
				if(f[i][j][sta]>f[i][j][s]+f[i][j][sta-s]-a[i][j]){
					f[i][j][sta]=f[i][j][s]+f[i][j][sta-s]-a[i][j];
					pre[i][j][sta]=tup(i,j,s);
				}
			}if(f[i][j][sta]!=inf){q.push(par(i,j));vis[i][j]=1;}
		}spfa(sta);
	}
	int x,y;
	for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(!a[i][j]){x=i;y=j;break;}
	printf("%d\n",f[x][y][(1<<K)-1]);
	dfs(x,y,(1<<K)-1);	
	for(int i=0;i<n;i++)
	for(int j=0;j<m;j++){
		if(!a[i][j])putchar('x');
		else if(vis[i][j])putchar('o');
		else putchar('_');if(j==m-1)puts("");
	}
	return 0;
}


你可能感兴趣的:(bzoj)