题解思路(按做题啵啵啵流程)
一、看到“最少走几步”先想到: BFS 最短路
因为:每走一步代价都一样
所以:第一次到终点,一定是最短步数
二、普通 BFS 够不够?
普通 BFS 状态:(x,y) 表示:人在什么位置但这题有:钥匙 K,门 D. 有没有钥匙会影响后面能不能走
所以:同一个位置可能有不同意义
例如:未来能走的路不同。因此:必须把“钥匙状态”加入 BFS。
(3,5,没钥匙)
(3,5,有钥匙)
三、状态设计
我们定义:x,y -> 当前位置即为:step -> 已经走了几步key -> 有没有钥匙
struct Node{
int x,y,step,key;
};
四、vis 为什么三维
同一个点,可能有两种状态,所以用vis[x][y][k]
五、BFS 转移流程例如:vis[x][y][0] (没钥匙来过)vis[x][y][1] (有钥匙来过)
每次从队列取出当前状态:
当前位置然后:
当前步数
是否有钥匙
1. 枚举四个方向:上下左右
2. 墙不能走
3. 门的判断
如果:
下一格是 D
并且没有钥匙
则不能进入。
4. 判断是否拿到钥匙
如果到K:则下一状态变成有钥匙5. 判重
如果:这个状态以前出现过,就不需要再搜索。
6. 入队
新的状态进入队列继续 BFS。
六、代码
#include<bits/stdc++.h>
using namespace std;
const int N=505;
char g[N][N]; // 地图
int h,w; // 地图高度和宽度
int sx,sy; // 起点坐标
// vis[x][y][k]
// k=0 表示没拿钥匙到达这里
// k=1 表示拿了钥匙到达这里
bool vis[N][N][2];
// 四个方向
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
// BFS队列中的状态
struct Node{
int x,y; // 当前坐标
int step; // 走了多少步
int key; // 是否拿到钥匙
};
void bfs(){
queue<Node> q;
// 从起点开始
q.push({sx,sy,0,0});
// 起点且没钥匙的状态标记已访问
vis[sx][sy][0]=1;
while(!q.empty()){
auto t=q.front();
q.pop();
int x=t.x;
int y=t.y;
int step=t.step;
int key=t.key;
// 到达终点
if(g[x][y]=='E'){
cout<<step;
return;
}
// 枚举四个方向
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
// 墙不能走
if(g[nx][ny]=='W') continue;
// 门D必须有钥匙才能进
if(g[nx][ny]=='D' && key==0) continue;
// 默认钥匙状态不变
int nkey=key;
// 如果遇到钥匙K
// 更新成已经拿到钥匙
if(g[nx][ny]=='K') nkey=1;
// 这个状态访问过
if(vis[nx][ny][nkey]) continue;
// 标记访问
vis[nx][ny][nkey]=1;
// 加入队列
q.push({nx,ny,step+1,nkey});
}
}
// 无法到达终点
cout<<-1;
}
int main(){
cin>>h>>w;
// 读入地图
for(int i=0;i<h;i++){
for(int j=0;j<w;j++){
cin>>g[i][j];
// 记录起点
if(g[i][j]=='S'){
sx=i;
sy=j;
}
}
}
bfs();
}

京公网安备 11010502036488号