题解 P9351【[JOI 2023 Final] Maze】
注意到,如果我们现在处于
其中第一种移动方式还可以拆分成一次向四连通格子移动和
初始时位于起点,高度为
若当前高度为
若当前高度为
若当前高度不为
问需要多少代价到达终点,高度不限。
我们以代价(从小到大)为第一关键字,高度(从高到低)为第二关键字,跑 01 BFS 即可。
时间复杂度为
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int dx4[4] = {-1, 0, 0, 1};
const int dy4[4] = {0, -1, 1, 0};
const int dx8[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int dy8[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
const int _ = 6e6 + 10;
int n, m, k, sx, sy, tx, ty;
bool arr[_], vis[_];
inline bool check(int x, int y) {
return (x >= 1 && x <= n && y >= 1 && y <= m);
}
inline int id(int x, int y) {
return (x - 1) * m + y;
}
struct node {
int x, y, t, h;
};
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> k;
cin >> sx >> sy;
cin >> tx >> ty;
for (int i = 1; i <= n; i++) {
string str;
cin >> str;
for (int j = 1; j <= m; j++) {
arr[id(i, j)] = (str[j-1] == '#');
}
}
deque<node> Q(1, (node){sx, sy, 0, 0});
while (true) {
node N = Q.front();
Q.pop_front();
int x = N.x;
int y = N.y;
int t = N.t;
int h = N.h;
if (vis[id(x, y)]) continue;
vis[id(x, y)] = true;
if (x == tx && y == ty) {
cout << t << endl;
return 0;
}
if (h) {
for (int d = 0; d <= 7; d++) {
int xx = x + dx8[d];
int yy = y + dy8[d];
if (check(xx, yy) && !vis[id(xx, yy)]) {
Q.push_back((node){xx, yy, t, h-1});
}
}
} else {
for (int d = 0; d <= 3; d++) {
int xx = x + dx4[d];
int yy = y + dy4[d];
if (check(xx, yy) && !vis[id(xx, yy)]) {
if (arr[id(xx, yy)]) {
Q.push_back((node){xx, yy, t+1, k-1});
} else {
Q.push_front((node){xx, yy, t, 0});
}
}
}
}
}
}