jzoj 4389. 【GDOI2016模拟3.15】圈地游戏 状压dp

Description
这里写图片描述

Input
这里写图片描述

Output
这里写图片描述

Sample Input

7 7
…….
.1###2.
.#…#.
.#.B.#.
.3…4.
..##…
……S
100
100
100
100

Sample Output

364

Data Constraint
这里写图片描述

Hint
这里写图片描述

分析:
与(jzoj 4016. 【雅礼联考DAY01】圈地为王 状压dp+bfs转移)是一样的,不过这题是在格上走,那题是在点上走。我们记录的状态可以看做是走到一个格子的最右边,所以往右边走状态要根据下一个格改变,往左走要根据起点的格子改变。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>

const int maxn=21;
const int dx[4]={1,0,-1,0};
const int dy[4]={0,1,0,-1};

using namespace std;

int f[maxn][maxn][256];
int n,m,cnt1,cnt2,stx,sty;
int a[maxn][maxn],v[maxn][maxn][256];

struct node{
    int x,y,v;
}g[10],b[10];

struct rec{
    int x,y,s;
};

queue <rec> q;

void init()
{
    char s[30];
    scanf("%d%d\n",&n,&m);
    for (int i=1;i<=n;i++)
    {
        scanf("%s",s);
        for (int j=1;j<=m;j++)
        {
            if ((s[j-1]=='.') || (s[j-1]=='S'))
            {
                a[i][j]=1;
                if (s[j-1]=='S') stx=i,sty=j;
            }
            else
            {
                a[i][j]=0;
                if (s[j-1]=='B') b[++cnt2]=(node){i,j,0};
                if ((s[j-1]>='1') && (s[j-1]<='8'))
                {
                    cnt1++;
                    g[s[j-1]-'0']=(node){i,j,0};
                }
            }
        }
    }
    for (int i=1;i<=cnt1;i++) scanf("%d",&g[i].v);
}

void dp()
{
    memset(f,0x3f3f3f3f,sizeof(f));
    f[stx][sty][0]=0;
    q.push((rec){stx,sty,0});
    v[stx][sty][0]=1;
    while (!q.empty())
    {       
        rec u=q.front();
        int x=u.x,y=u.y,s=u.s;
        q.pop();    
        for (int i=0;i<4;i++)
        {
            int xx=x+dx[i],yy=y+dy[i];
            if ((xx>0) && (yy>0) && (xx<=n) && (yy<=m))
            {
                if ((xx==1) && (yy==2))
                  int k=0;
                if (a[xx][yy])
                {
                    int sub=s;
                    if (i==1)
                    {
                        for (int j=1;j<=cnt1;j++)
                        {
                            if ((xx<g[j].x) && (yy==g[j].y)) sub^=1<<(j-1);
                        }
                        for (int j=1;j<=cnt2;j++)
                        {
                            if ((xx<b[j].x) && (yy==b[j].y)) sub^=1<<(cnt1+j-1);
                        }
                    }
                    if (i==3)
                    {
                        for (int j=1;j<=cnt1;j++)
                        {
                            if ((xx<g[j].x) && (yy+1==g[j].y)) sub^=1<<(j-1);
                        }
                        for (int j=1;j<=cnt2;j++)
                        {
                            if ((xx<b[j].x) && (yy+1==b[j].y)) sub^=1<<(cnt1+j-1);
                        }
                    }
                    if (f[xx][yy][sub]>f[x][y][s]+1)
                    {
                        f[xx][yy][sub]=f[x][y][s]+1;
                        if (!v[xx][yy][sub])
                        {
                            v[xx][yy][sub]=1;
                            q.push((rec){xx,yy,sub});
                        } 
                    }
                }
            }
        }
        v[x][y][s]=0;
    }
}

int calc(int x)
{
    int sum=0,t=1<<(cnt1-1),k=cnt1;
    while (x>0)
    {
        if (x>=t) sum+=g[k].v,x-=t;
        t/=2;
        k--; 
    }
    return sum;
}

int main()
{
    init();         
    dp();       
    int ans=0;      
    for (int i=0;i<(1<<cnt1);i++)
    {
        int d=calc(i);
        ans=max(ans,d-f[stx][sty][i]);
    }
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/81118479