bzoj2595 [Wc2008]遊覽計劃 斯坦納樹
阿新 • • 發佈:2018-11-05
Description
Solution
一開始還以為是什麼奇妙的網路流。。
斯坦納樹裸題。所謂斯坦納樹就是求原圖的一個子圖,使得給定點集連通且邊權之和最小。大概是最小生成樹的拓展
設f[i,x]表示給定點集的連通性為i,下一條邊可以從與x相鄰的邊中選的答案,我們可以
- 列舉i的子集設為j,f[i,x]=min(f[i,x],f[j,x]+f[i-j,x])
- 列舉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;
}