思路

  • 总体思路是用BFS找最短路
  • 由于拿到钥匙和没拿到钥匙两种状态对应的地图的形态不一样
    • 拿到钥匙时'D'可以通过,因此可以看作'.'
  • 可以从分层图的角度考虑问题,第一层地图是没拿到钥匙的地图,第二层地图是拿到钥匙的地图。
  • BFS遇到钥匙时,不仅要在第一层图的四个方向继续尝试搜索,还要将第二层地图的'K'位置放入队列中(相当于在第二层图上开始BFS,向队列中放入第一个节点的步骤)
    代码
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int MAX = 510;
char g[MAX][MAX];
int dist[MAX][MAX][2];
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
int N, M;
struct Node {
	int x, y, z;
};

int solve() {
	int r, c;
	
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if (g[i][j] == 'S') {
				r = i, c = j;
			}
		}
	}
	
	memset(dist, -1, sizeof dist);
	
	queue<Node> q;
	q.push({r, c, 0});
	dist[r][c][0] = 0;
	
	int ans = -1;
	
	while (q.size()) {
		Node t = q.front();
		q.pop();
		
		if (g[t.x][t.y] == 'E') {
			ans = dist[t.x][t.y][t.z];
			break;
		}
		
		if (t.z == 0 && g[t.x][t.y] == 'K') {
			q.push({t.x, t.y, 1});
			dist[t.x][t.y][1] = dist[t.x][t.y][0];
		}
		
		for (int i = 0; i < 4; i++) {
			int nx = t.x + dx[i];
			int ny = t.y + dy[i];
			if (nx < 0 || nx >= N || ny < 0 || ny >= M) continue;
			if (dist[nx][ny][t.z] != -1 || g[nx][ny] == 'W' || t.z == 0 && g[t.x][t.y] == 'D') continue;
			q.push({nx, ny, t.z});
			dist[nx][ny][t.z] = dist[t.x][t.y][t.z] + 1;
		}
		
	}
	
	return ans;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	
	cin >> N >> M;
	
	for (int i = 0; i < N; i++) cin >> g[i];
	
	int ans = solve();
	
	cout << ans << '\n';
	
	return 0;
}