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

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/83443132

Description


在这里插入图片描述

在这里插入图片描述

Solution


一开始还以为是什么奇妙的网络流。。

斯坦纳树裸题。所谓斯坦纳树就是求原图的一个子图,使得给定点集连通且边权之和最小。大概是最小生成树的拓展
设f[i,x]表示给定点集的连通性为i,下一条边可以从与x相邻的边中选的答案,我们可以

  1. 枚举i的子集设为j,f[i,x]=min(f[i,x],f[j,x]+f[i-j,x])
  2. 枚举x的邻点设为y,f[i,x]=min(f[i,x],f[i,y]+w[x,y])
    第一个转移可以直接上,第二个转移可以用最短路松弛。注意这里是一般的模型,权值都在边上

本题就是f[i,j,x]表示i行j列状态为x的答案,转移的时候注意权值在点上就可以了
输出方案的话每次记录转移方式,然后dfs即可

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))

const int INF=0x3f3f3f3f;
const int N=12;

int f[N][N][(1<<N)+5];
int a[N][N],wjp[N][N][(1<<N)+5];
int xx[N][N][(1<<N)+5],yy[N][N][(1<<N)+5];
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int id[N][N],n,m;

bool prt[N][N],vis[N][N];

std:: queue <int> que;

void dfs(int x,int y,int now) {
	prt[x][y]=true;
	if (!f[x][y][now]) return ;
	if (wjp[x][y][now]) dfs(xx[x][y][now],yy[x][y][now],now);
	else {
		dfs(x,y,xx[x][y][now]);
		dfs(x,y,yy[x][y][now]);
	}
}

void spfa(int rec) {
	for (;!que.empty();) {
		int x=que.front(); que.pop();
		int y=que.front(); que.pop();
		rep(k,0,3) {
			int tx=x+dx[k],ty=y+dy[k];
			if (!tx||!ty||tx>n||ty>m) continue;
			if (x&&f[x][y][rec]+a[tx][ty]<f[tx][ty][rec]) {
				f[tx][ty][rec]=f[x][y][rec]+a[tx][ty];
				wjp[tx][ty][rec]=1;
				xx[tx][ty][rec]=x;
				yy[tx][ty][rec]=y;
				if (!vis[tx][ty]) {
					que.push(tx); que.push(ty);
					vis[tx][ty]=true;
				}
			}
		} vis[x][y]=false;
	}
}

int main(void) {
	int cnt=0; scanf("%d%d",&n,&m);
	fill(f,31);
	rep(i,1,n) rep(j,1,m) {
		scanf("%d",&a[i][j]);
		if (!a[i][j]) {
			cnt++;
			f[i][j][1<<(cnt-1)]=0;
		}
	}
	rep(now,1,(1<<cnt)-1) {
		fill(vis,0);
		rep(i,1,n) rep(j,1,m) {
			for (int tmp=(now-1)&now;tmp;tmp=(tmp-1)&now) {
				if (f[i][j][tmp]+f[i][j][now-tmp]-a[i][j]<f[i][j][now]) {
					wjp[i][j][now]=0;
					xx[i][j][now]=tmp;
					yy[i][j][now]=now-tmp;
					f[i][j][now]=f[i][j][tmp]+f[i][j][now-tmp]-a[i][j];
				}
			}
			if (f[i][j][now]!=f[0][0][0]) que.push(i),que.push(j),vis[i][j]=true;
		}
		spfa(now);
	}
	int ans=INF,stx,sty;
	rep(i,1,n) rep(j,1,m) if (!a[i][j]) {
		if (f[i][j][(1<<cnt)-1]<ans) {
			ans=f[i][j][(1<<cnt)-1];
			stx=i,sty=j;
		}
	}
	printf("%d\n", ans);
	dfs(stx,sty,(1<<cnt)-1);
	rep(i,1,n) {
		rep(j,1,m) {
			if (!a[i][j]) putchar('x');
			else if (prt[i][j]) putchar('o');
			else putchar('_');
		} puts("");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/83443132
今日推荐