洛谷4011 孤岛营救问题(BFS)(状态压缩)

版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/83145394

题目

1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图。迷宫的外形是一个长方形,其南北方向被划分为 N 行,东西方向被划分为 M 列,于是整个迷宫被划分为 N×M 个单元。每一个单元的位置可用一个有序数对(单元的行号,单元的列号)来表示。南北或东西方向相邻的 2 个单元之间可能互通,也可能有一扇锁着的门,或者是一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,并且所有的门被分成P 类,打开同一类的门的钥匙相同,不同类门的钥匙不同。

大兵瑞恩被关押在迷宫的东南角,即(N,M) 单元里,并已经昏迷。迷宫只有一个入口,在西北角。也就是说,麦克可以直接进入 (1,1)单元。另外,麦克从一个单元移动到另一个相邻单元的时间为 1,拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。

试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。

题解

BFS+状态压缩
S才14果断状压拿了多少把钥匙。
设vis[x][y][t]表示到(x,y)且钥匙状态为t时的最短时间,很显然每个位置每个状态只能走一次。

代码

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=1<<30;
const int maxn=12;
const int dx[]={0,0,-1,1},dy[]={-1,1,0,0};
int n,m,p;
vector<int> key[maxn][maxn];
int ma[maxn][maxn][maxn][maxn];
int vis[maxn][maxn][(1<<14)+10];

struct U{int x,y,t;};
queue<U> q;

void bfs()
{
    int t0=0;
    for(int i=0;i<key[1][1].size();i++) t0|=1<<key[1][1][i]-1;
    q.push((U){1,1,t0});vis[1][1][t0]=1;
    while(!q.empty())
    {
        int x=q.front().x,y=q.front().y,t=q.front().t;q.pop();
        for(int i=0;i<4;i++)
        {
            int nx=x+dx[i],ny=y+dy[i],nt=t;
            if(1>nx||nx>n || 1>ny||ny>m) continue;
            if(ma[x][y][nx][ny]==-1) continue;
            if(!ma[x][y][nx][ny] || (t>>ma[x][y][nx][ny]-1)&1)//p>>ma[x][y][nx][ny]-1
            {
                for(int j=0;j<key[nx][ny].size();j++) nt|=1<<key[nx][ny][j]-1;
                if(vis[nx][ny][nt]) continue;vis[nx][ny][nt]=vis[x][y][t]+1;
                q.push((U){nx,ny,nt});
//                printf("q: %d %d %d - %d\n",nx,ny,nt,vis[nx][ny][nt]);
            }
        }
    }
}

int main()
{
    scanf("%d%d%d",&n,&m,&p);
    int K;scanf("%d",&K);
    for(int i=1;i<=K;i++)
    {
        int x1,y1,x2,y2,g;
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&g);
        if(!g) ma[x1][y1][x2][y2]=ma[x2][y2][x1][y1]=-1;
        else ma[x1][y1][x2][y2]=ma[x2][y2][x1][y1]=g;
    }
    int S;scanf("%d",&S);
    for(int i=1;i<=S;i++)
    {
        int x,y,q;
        scanf("%d%d%d",&x,&y,&q);
        key[x][y].push_back(q);
    }
    bfs();
    int ans=inf;
    for(int i=0,imax=1<<p;i<imax;i++) ans=min(ans,!vis[n][m][i]?inf:vis[n][m][i]);//debug imax=1<<p-1 max(ans,vis[n][m][i])
    if(ans!=inf) printf("%d\n",ans-1);
    else puts("-1");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/83145394