#斯坦纳树#洛谷 4294 [WC2008]游览计划 分析 代码

#斯坦纳树#洛谷 4294 [WC2008]游览计划
分析
代码

题目


几乎就是模板题,考虑不同点就是它是点权,
所以在求两个子集的时候要减去这个点的点权,
还有一点恶心的就是要输出方案,令人作呕


代码

#include <cstdio>
#include <cctype>
#include <queue>
#include <cstring>
#define rr register
using namespace std;
const int N=101,M=1051; queue<int>q;
struct node{int y,w,next;}e[M<<2]; pair<int,int>pre[M][N];
int dp[M][N],v[N],two[11],p[N],as[N],a[N],n,m,al,k=1,tot;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed rk(int x,int y){return (x-1)*m+y;}
inline void add(int x,int y,int w){e[++k]=(node){y,w,as[x]},as[x]=k;}
inline void Spfa(int z){
	while (q.size()){
		rr int x=q.front(); q.pop();
		for (rr int i=as[x];i;i=e[i].next)
		if (dp[z][e[i].y]>dp[z][x]+e[i].w){
			dp[z][e[i].y]=dp[z][x]+e[i].w;
			pre[z][e[i].y]=make_pair(z,x);
			if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y);
		}
		v[x]=0;
	}
}
inline void dfs(int S,int now){
	if (!pre[S][now].first) return;
	v[now]=1;
	if (pre[S][now].second==now)
	    dfs(pre[S][now].first^S,now);
	dfs(pre[S][now].first,pre[S][now].second);
}
signed main(){
	memset(dp,0x3f,sizeof(dp));
	n=iut(),m=iut(),tot=n*m,two[0]=1;
	for (rr int i=1;i<11;++i) two[i]=two[i-1]<<1;
	for (rr int i=1;i<=n;++i)
	for (rr int j=1,RK;j<=m;++j){
	    RK=rk(i,j),a[RK]=iut();
	    if (!a[RK]) p[al++]=RK;
	    if (j>1) add(RK,rk(i,j-1),a[rk(i,j-1)]),add(rk(i,j-1),RK,a[RK]);
	    if (i>1) add(RK,rk(i-1,j),a[rk(i-1,j)]),add(rk(i-1,j),RK,a[RK]);
	}
	for (rr int i=0;i<al;++i) dp[two[i]][p[i]]=0;
	for (rr int S=0;S<two[al];++S){
		memset(v,0,sizeof(v));
		for (rr int i=1;i<=tot;++i){
			for (rr int j=S&(S-1);j;j=(j-1)&S)
			if (dp[S][i]>dp[j][i]+dp[S^j][i]-a[i]){
				dp[S][i]=dp[j][i]+dp[S^j][i]-a[i];
				pre[S][i]=make_pair(j,i);
			}
			if (dp[S][i]^dp[0][0]) q.push(i),v[i]=1;
		}
		Spfa(S);
	}
	printf("%d",dp[two[al]-1][p[0]]);
	dfs(two[al]-1,p[0]);
	for (rr int i=1,tot=0;i<=n;++i){
	    putchar(10);
		for (rr int j=1;j<=m;++j)
		if (rk(i,j)==p[tot]) ++tot,putchar('x');
		    else if (v[rk(i,j)]) putchar('o');
		        else putchar('_');
	}
	return 0;
}