Luogu P4294 [WC2008]游览计划

斯坦纳树。

\(f[i][j][s]\) 表示当前 \((i,j)\) 覆盖关键点的状态为 \(s\) 的最小代价。

\(f[i][j][s]=\min(f[i][j][s],f[i][j][s\ {\rm xor}\ t]+f[i][j][t]-a[i][j])\)

\(f[i+{\rm dx}][j+{\rm dy}][s]=min(f[i+{\rm dx}][j+{\rm dy}][s],f[i][j][s]+a[i+{\rm dx}][j+{\rm dy}])\)

第一个式子直接DP;第二个式子在第一个式子DP完后跑一边spfa即可。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=20,Inf=0x3f3f3f3f,dx[]={0,-1,0,1},dy[]={1,0,-1,0};
int n,m,tot,sx,sy;
int a[N][N],f[N][N][1<<11];
bool vis[N][N],ans[N][N];
struct node {int x,y,s;}lst[N][N][1<<11];
struct pt {int x,y;};
queue<pt> q;
inline void spfa(int s) {
  while(q.size()) {
    R x=q.front().x,y=q.front().y; q.pop();
    vis[x][y]=false;
    for(R i=0;i<4;++i) {
      R xx=x+dx[i],yy=y+dy[i];
      if(xx<1||xx>n||yy<1||yy>m) continue;
      if(f[x][y][s]+a[xx][yy]<f[xx][yy][s]) {
        f[xx][yy][s]=f[x][y][s]+a[xx][yy];
        if(!vis[xx][yy]) 
          q.push((pt){xx,yy}),vis[xx][yy]=true;
        lst[xx][yy][s]=(node){x,y,s};
      }
    }
  }
}
inline void dfs(int x,int y,int s) {
  if(!lst[x][y][s].s) return ;
  ans[x][y]=1;
  R i=lst[x][y][s].x,j=lst[x][y][s].y,t=lst[x][y][s].s;
  dfs(i,j,t);
  if(i==x&&j==y) dfs(i,j,s^t);
}
inline void main() {
  n=g(),m=g(),tot=0;
  memset(f,0x3f,sizeof f);
  for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) {
    a[i][j]=g();
    if(!a[i][j]) sx=i,sy=j,f[i][j][1<<tot]=0,++tot;
  }
  for(R s=1,lim=1<<tot;s<lim;++s) {
    while(q.size()) q.pop();
    for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) {
      for(R t=s;t;t=s&(t-1)) 
        if(f[i][j][s]>f[i][j][t]+f[i][j][s^t]-a[i][j]) {
          f[i][j][s]=f[i][j][t]+f[i][j][s^t]-a[i][j];
          lst[i][j][s]=(node){i,j,t};
        }
      if(f[i][j][s]!=Inf) 
        q.push((pt){i,j}),vis[i][j]=true;
    }
    spfa(s);
  }
  printf("%d\n",f[sx][sy][(1<<tot)-1]);
  dfs(sx,sy,(1<<tot)-1);
  for(R i=1;i<=n;++i,putchar(10)) for(R j=1;j<=m;++j) {
    if(!a[i][j]) {putchar('x'); continue;}
    putchar(ans[i][j]?'o':'_');
  } 
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.18

posted @ 2020-01-18 11:13  LuitaryiJack  阅读(138)  评论(0编辑  收藏  举报