menu ZigZagK的博客
account_circle

正在努力加载中QAQ

[斯坦纳树]BZOJ2595(Wc2008)【游览计划】题解
apps DP,BZOJ
local_offer 查看标签
comment 2 条评论

题目概述

在 $n\times m$ 的网格上有 $k$ 个景点,选取每个网格都有代价,求最小代价使得景点之间全部连通。

解题报告

感觉这个东西好mogical啊……定义 $f_{i,j,s}$ 表示当 $i,j$ 与 $s$ 这些景点连通时的最优解,那么有两种方法转移:

  • 通过子集转移:$f_{i,j,t}+f_{i,j,s-t}-cost_{i,j}\to f_{i,j,s}$ ,减去 $cost_{i,j}$ 是因为算重复了。
  • 通过相邻点转移:$f_{x,y,s}+cost_{i,j}\to f_{i,j,s}$ 。

但是这个DP后效性已经飞天了,由于第二种转移和最短路长得很像,所以考虑用Spfa(没错就是SpfaQAQ)进行,每次先用第一种转移处理出 $f_{i,j,s}$ ,然后把 $f_{i,j,s}$ 加进队列,对每个 $s$ 都做一遍Spfa。

复杂度……可能是 $O(n^23^n+n^22^n)=O(n^23^n)$ ?至于为什么叫这个名字,我怎么知道。

示例程序

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=10,maxk=10,maxs=1<<maxk,maxt=maxn*maxn;
const int dif[4][2]={{-1,0},{1,0},{0,-1},{0,1}};

int n,m,K,pic[maxn+5][maxn+5],f[maxn+5][maxn+5][maxs];
struct data {int i,j,s;} fa[maxn+5][maxn+5][maxs],que[maxt+5];
int INF,Head,Tail;bool vis[maxn+5][maxn+5];

inline bool Fix(int &x,int y) {if (y<x) return x=y,true;return false;}
#define AM(x) ((x)<maxt?(x)+1:0)
inline void Spfa(int s){
    while (Head!=Tail){
        data now=que[Head=AM(Head)];int x=now.i,y=now.j;vis[x][y]=false;
        for (int t=0;t<4;t++){
            int xx=x+dif[t][0],yy=y+dif[t][1];if (xx<1||xx>n||yy<1||yy>m) continue;
            if (Fix(f[xx][yy][s],f[x][y][s]+pic[xx][yy])){
                fa[xx][yy][s]=(data){x,y,s};if (vis[xx][yy]) continue;
                que[Tail=AM(Tail)]=(data){xx,yy,s};vis[xx][yy]=true;
            }
        }
    }
}
void Path(int x,int y,int s){
    if (!x&&!y) return;data now=fa[x][y][s];int i=now.i,j=now.j,t=now.s;
    vis[x][y]=true;Path(i,j,t);if (x==i&&y==j) Path(i,j,s^t);
}
int main(){
    freopen("program.in","r",stdin);freopen("program.out","w",stdout);
    scanf("%d%d",&n,&m);memset(f,63,sizeof(f));INF=f[0][0][0];int X,Y;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            scanf("%d",&pic[i][j]),pic[i][j]?0:f[X=i][Y=j][1<<K++]=0;
    for (int s=1;s<(1<<K);Spfa(s),s++,Head=Tail=0){
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++){
                for (int t=(s-1)&s;t;t=(t-1)&s)
                    if (Fix(f[i][j][s],f[i][j][t]+f[i][j][s^t]-pic[i][j]))
                        fa[i][j][s]=(data){i,j,t};
                if (f[i][j][s]<INF) que[Tail=AM(Tail)]=(data){i,j,s},vis[i][j]=true;
            }
    }printf("%d\n",f[X][Y][(1<<K)-1]);Path(X,Y,(1<<K)-1);
    for (int i=1;i<=n;i++,puts(""))
        for (int j=1;j<=m;j++) putchar(!pic[i][j]?'x':(vis[i][j]?'o':'_'));return 0;
}
版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处!
名称不能为空
email
邮箱不能为空,请填写正确格式
link
网址请用http://或https://开头
message
评论不能为空
资瓷Markdown和LaTeX数学公式
sentiment_very_satisfied
    2019-03-31 16:35:38Gnekiah
    keyboard_arrow_down
    2019-03-31 16:35:38

    Tex 解析好像出了点问题.(⊙0⊙)

    remove_red_eye
    访客
      2019-04-04 19:34:28ZigZagK
      keyboard_arrow_down
      2019-04-04 19:34:28
      @Gnekiah 

      啊?我好像没发现QAQ,请问能说的具体点吗QAQ

      account_circle
      博主
keyboard_arrow_up