[NOI Online #2 入門組] 荊軻刺秦王(記憶化搜索) | 錯題本

題目

[NOI Online #2 入門組] 荊軻刺秦王

分析

記憶化 BFS。記錄 T[x][y][c1][c2] (c1C1,c2C2)T[x][y][c_1][c_2]\ (c_1 \leq C_1, c_2 \leq C_2) 表示能否恰好用 c1c_1 次隱身和 c2c_2 次瞬移從起始位置走到 xxyy 列,Num[x][y]Num[x][y] 表示走到 xxyy 列保證最短時間(BFS 本身就能保證)下的最小 c1+c2c_1 + c_2 值。

錯因

  • 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章