bzoj2595 [Wc2008]游览计划

题目描述

题解:

这道题是斯坦纳树的典型例题。

首先看一眼数据范围发现$10$的范围不状压对不起出题人,然后考虑转移。

设$f[i][j][s]$表示当前在点$(i,j)$,覆盖特殊节点状态为$s$的最小花费。

转移有:

1.$s$不变,此时有$f[i][j][s]=min(f[i'][j'][s]+a[i'][j'])$;

2.$(i,j)$不变,此时有$f[i][j][s]=min(f[i][j][t]+f[i][j][s$^$t])$,其中$t$是$s$的子集。

转移1是最短路形式,我们可用spfa转移;

转移2直接枚举子集。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 15
int n,m;
int f[N][N][1<<10],mp[N][N];
int cnt;
struct Pair
{
    int x,y;
    Pair(){}
    Pair(int x,int y):x(x),y(y){}
}p[N];
struct Three
{
    int x,y,s;
    Three(){}
    Three(int x,int y,int s):x(x),y(y),s(s){}
}fa[N][N][1<<10];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
bool vis[N][N];
queue<Pair>q;
bool check(int x,int y)
{
    return x>=1&&x<=n&&y>=1&&y<=m;
}
void spfa(int s)
{
    while(!q.empty())
    {
        Pair tp = q.front();
        q.pop();
        int x = tp.x,y = tp.y,tx,ty;
        for(int i=0;i<4;i++)
        {
            tx = x+dx[i],ty = y+dy[i];
            if(!check(tx,ty))continue;
            if(f[x][y][s]+mp[x][y]<f[tx][ty][s])
            {
                f[tx][ty][s]=f[x][y][s]+mp[x][y];
                fa[tx][ty][s] = Three(x,y,s);
                if(!vis[tx][ty])
                {
                    q.push(Pair(tx,ty));
                    vis[tx][ty] = 1;
                }
            }
        }
        vis[x][y] = 0;
    }
}
bool ot[N][N];
void dfs(int x,int y,int s)
{
    if(!check(x,y))return ;
    ot[x][y] = 1;
    Three tmp = fa[x][y][s];
    if(tmp.s==s)
    {
        dfs(tmp.x,tmp.y,s);
    }else
    {
        dfs(tmp.x,tmp.y,tmp.s);
        dfs(tmp.x,tmp.y,s^tmp.s);
    }
}
int main()
{
//        freopen("7.in","r",stdin);
    scanf("%d%d",&n,&m);
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&mp[i][j]);
            if(!mp[i][j])
            {
                p[cnt] = Pair(i,j);
                f[i][j][1<<cnt] = 0;
                cnt++;
            }
        }
    }
    for(int s = 1;s<(1<<cnt);spfa(s),s++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                for(int t=s&(s-1);t;t=(t-1)&s)
                    if(f[i][j][s]>f[i][j][s^t]+f[i][j][t])
                    {
                        f[i][j][s]=f[i][j][s^t]+f[i][j][t];
                        fa[i][j][s] = Three(i,j,t);
                    }
                if(f[i][j][s]<0x3f3f3f3f)q.push(Pair(i,j)),vis[i][j]=1;
            }
    printf("%d\n",f[p[0].x][p[0].y][(1<<cnt)-1]);
    dfs(p[0].x,p[0].y,(1<<cnt)-1);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(!mp[i][j])putchar('x');
            else if(ot[i][j])putchar('o');
            else putchar('_');
        }
        puts("");
    }
    return 0;
}

 

posted @ 2019-01-02 07:24  LiGuanlin  阅读(75)  评论(0编辑  收藏  举报