BZOJ2595. [Wc2008]游览计划

【题意】

N*M的图中,有k个关键点,除了关键点外每个点有点权,请你用最小的费用使得景点之间联通

【分析】

这是斯坦纳树的模板题

设F[i][s]表示以i为根的子树内,选择的关键点状态为s的最小代价

外层枚举状态S

然后考虑转移:

1.由自己的其他状态转移来F[i][s]=min{F[i][t]+F[i][s^t]}

2.由其他边走过来F[i][s]=min{F[i][s],F[j][s]+e[j][i]}

第二个式子这种三角形不等式可以spfa转移一下

注意这个题是点权,在第一种转移的时候记得减去算重复的点权即可

 

【代码】

#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define fi first
#define se second
#define lson now<<1
#define rson now<<1|1
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3f3f3f3f;
const int maxn=1025;
int n,m;
int a[12][12],f[12][12][maxn];
int cnt,vis[12][12];
int posx,posy;
struct path
{
    int i,j,s;
}pre[12][12][maxn];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
queue <PII> q;
void spfa(int st)
{
    while(!q.empty())
    {
        PII u=q.front(); q.pop();
        vis[u.fi][u.se]=0;
        for(int i=0;i<4;i++)
        {
            int tox=u.fi+dx[i];
            int toy=u.se+dy[i];
            if(tox>n || toy>m || tox<1 || toy<1) continue;
            if(f[tox][toy][st]>f[u.fi][u.se][st]+a[tox][toy])
            {
                f[tox][toy][st]=f[u.fi][u.se][st]+a[tox][toy];
                pre[tox][toy][st]=(path){u.fi,u.se,st};
                if(!vis[tox][toy])
                {
                    vis[tox][toy]=1;
                    q.push(mp(tox,toy));
                }
            }
        }
    }
}
void dfs(int x,int y,int st)
{
    vis[x][y]=1;
    int tx=pre[x][y][st].i,ty=pre[x][y][st].j,ts=pre[x][y][st].s;
    if(!tx && !ty) return;
    dfs(tx,ty,ts);
    if(x==tx && y==ty) dfs(tx,ty,st-ts);
}
int main()
{

    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",&a[i][j]);
            if(!a[i][j])
            {
                if(!posx)
                 posx=i,posy=j;
                f[i][j][1<<cnt]=0;
                cnt++;
            }
        }
    for(int s=0;s<(1<<cnt);s++)
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                for(int st=s;st;st--)
                {
                    if((st|s)!=s) continue;
                    if(f[i][j][s]>f[i][j][st]+f[i][j][s-st]-a[i][j])
                    {
                        f[i][j][s]=f[i][j][st]+f[i][j][s-st]-a[i][j];
                        pre[i][j][s]=(path){i,j,st};
                    }
                }
                if(f[i][j][s]<inf) q.push(mp(i,j)),vis[i][j]=1;
            }
        spfa(s);
    }
    printf("%d\n",f[posx][posy][(1<<cnt)-1]);
    memset(vis,0,sizeof(vis));
    dfs(posx,posy,(1<<cnt)-1);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(!a[i][j]) printf("x");
            else
            {
                if(vis[i][j]) printf("o");
                else printf("_");      
            }
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2021-05-24 10:17  andyc_03  阅读(57)  评论(0编辑  收藏  举报