版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 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;
}