BZOJ 2595: [Wc2008]游览计划

斯坦纳树

Dijkstra+堆貌似慢了一倍

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,lim=1,F[12][12][1050],a[12][12],vis[12][12],instack[12][12];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
struct node{
	int x,y,sta;
}Pre[12][12][1050],q[1000005];
void spfa(int now){
//	printf("ans:%d\n",now);
	int head=0,tail=1;
	memset(instack,0,sizeof(instack));
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++){
			q[++tail]=(node){i,j,0};
			instack[i][j]=1;
		}
	while (head<tail){
		head++;
		int x=q[head].x,y=q[head].y;
		instack[x][y]=0;
		for (int i=0; i<4; i++){
			int fx=x+dx[i],fy=y+dy[i];
			if (fx<1 || fx>n || fy<1 || fy>m) continue;
			if (F[fx][fy][now]>F[x][y][now]+a[fx][fy]){
				F[fx][fy][now]=F[x][y][now]+a[fx][fy];
				Pre[fx][fy][now]=(node){x,y,now};
				if (!instack[fx][fy]){
					instack[fx][fy]=1;
					q[++tail]=(node){fx,fy,0};
				}
			}
		}
	}
}
void solve(int x,int y,int now){
	if (!now) return;
	int X=Pre[x][y][now].x,Y=Pre[x][y][now].y,sta=Pre[x][y][now].sta;
	solve(X,Y,sta);
	if (X==x && Y==y){
		if (sta) solve(X,Y,now-sta);
	}
	else vis[x][y]=1;
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++){
			scanf("%d",&a[i][j]);
			if (a[i][j]==0) lim<<=1;
		}
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++)
			for (int now=1; now<lim; now++)
				F[i][j][now]=1e9;
	int num=0;
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++)
			if (!a[i][j]) {
				F[i][j][1<<num]=0;
				num++;
			}
	for (int now=1; now<lim; now++){
		for (int i=1; i<=n; i++)
			for (int j=1; j<=m; j++)
				for (int sta=now; sta; sta=((sta-1)&now)){
					if (F[i][j][now]>F[i][j][sta]+F[i][j][now-sta]-a[i][j]){
						F[i][j][now]=F[i][j][sta]+F[i][j][now-sta]-a[i][j];
						Pre[i][j][now]=(node){i,j,sta};
					}
				}
		spfa(now);
	}
	int ansx=0,ansy=0;
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++)
			if (!a[i][j]){
				ansx=i,ansy=j;
				break;	
			}
	solve(ansx,ansy,lim-1);
	printf("%d\n",F[ansx][ansy][lim-1]);
	for (int i=1; i<=n; i++){
		for (int j=1; j<=m; j++)
			if (!a[i][j]) printf("x");
			else if (vis[i][j]) printf("o");
			else printf("_");
		printf("\n");
	}
	return 0;
}

  

posted @ 2018-10-15 14:32  ~Silent  阅读(117)  评论(0编辑  收藏  举报
Live2D