題目
分析
記憶化 BFS。記錄 表示能否恰好用 次隱身和 次瞬移從起始位置走到 行 列, 表示走到 行 列保證最短時間(BFS 本身就能保證)下的最小 值。
錯因
freopen
沒刪;- 輸入用的
getchar
本地運行結果跟 OJ 不同,應該用scanf
讀入字符數組; - 題意讀錯,以爲瞬移路徑上不能被觀察到,實際上瞬移過程無視守衛;
- 居然沒想過用 BFS,一上來就 DFS;
- 沒想到用差分處理曼哈頓距離的區間修改單點查詢。
代碼
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
const int MAXC = 15;
const int MAXN = 350;
const int INF = 0x3f3f3f3f;
inline int Abs(const int &x) {
return x < 0 ? -x : x;
}
const int Dir[8][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, 1}, {1, -1}, {-1, -1}, {-1, 1}};
int N, M, C1, C2, D;
int Num[MAXN + 5][MAXN + 5];
int Map[MAXN + 5][MAXN + 5], V[MAXN + 5][MAXN + 5];
bool T[MAXN + 5][MAXN + 5][MAXC + 5][MAXC + 5];
struct Node {
int x, y, t, c1, c2;
Node(int _x = 0, int _y = 0, int _t = 0, int _c1 = 0, int _c2 = 0) {
x = _x, y = _y, t = _t, c1 = _c1, c2 = _c2;
}
bool operator < (const Node &other) const {
if (t != other.t) return t < other.t;
else if (c1 + c2 != other.c1 + other.c2)
return c1 + c2 < other.c1 + other.c2;
else return c1 < other.c1;
}
};
inline bool Ok(const int &x, const int &y) {
return x >= 1 && x <= N && y >= 1 && y <= M && Map[x][y] <= 0 && Map[x][y] != -1;
}
int main() {
int X, Y, A, B;
scanf("%d%d%d%d%d", &N, &M, &C1, &C2, &D);
for (int i = 1; i <= N; i++)
for (int j = 1; j <= M; j++) {
char str[10]; scanf("%s", str);
int len = strlen(str);
for (int k = 0; k < len; k++) {
char c = str[k];
if (c == '.') Map[i][j] = 0;
else if (c == 'S') Map[A = i][B = j] = -1;
else if (c == 'T') Map[X = i][Y = j] = -2;
else Map[i][j] = Map[i][j] * 10 + (c ^ 48);
}
for (int x = 0; x <= Map[i][j] - 1; x++) {
int y = Map[i][j] - x - 1;
if (i - x >= 1)
V[i - x][std::max(1, j - y)]++, V[i - x][std::min(M, j + y) + 1]--;
if (i + x <= M)
V[i + x][std::max(1, j - y)]++, V[i + x][std::min(M, j + y) + 1]--;
}
}
for (int i = 1; i <= N; i++)
for (int j = 1; j <= M; j++)
V[i][j] += V[i][j - 1];
std::queue<Node> Q;
Q.push(Node(A, B, 0, 0, 0));
Num[A][B] = 0;
memset(Num, 0x3f, sizeof Num);
Node Ans = Node(X, Y, INF, INF, INF);
while (!Q.empty()) {
Node u = Q.front(); Q.pop();
if (u.x == X && u.y == Y) {
if (Ans.t < u.t)
break;
Ans = std::min(Ans, u);
}
int tx = 0, ty = 0;
for (int p = 0; p <= 1; p++) {
if (u.c1 + p > C1)
continue;
u.c1 += p;
for (int i = 0; i < 8; i++) {
if (i < 4 && u.c2 < C2) {
tx = u.x + Dir[i][0] * D, ty = u.y + Dir[i][1] * D;
if (Ok(tx, ty) && !T[tx][ty][u.c1][u.c2 + 1])
if ((!V[tx][ty] || p) && Num[tx][ty] > u.c1 + u.c2 + 1) {
Num[tx][ty] = u.c1 + u.c2 + 1;
T[tx][ty][u.c1][u.c2 + 1] = true;
Q.push(Node(tx, ty, u.t + 1, u.c1, u.c2 + 1));
}
}
tx = u.x + Dir[i][0], ty = u.y + Dir[i][1];
if (Ok(tx, ty) && !T[tx][ty][u.c1][u.c2])
if ((!V[tx][ty] || p) && Num[tx][ty] > u.c1 + u.c2) {
Num[tx][ty] = u.c1 + u.c2;
T[tx][ty][u.c1][u.c2] = true;
Q.push(Node(tx, ty, u.t + 1, u.c1, u.c2));
}
}
}
}
if (Ans.t == INF)
printf("-1");
else
printf("%d %d %d", Ans.t, Ans.c1, Ans.c2);
return 0;
}