mayoko’s diary

プロコンとかいろいろ。

AOJ 1178 A Broken Door

解法

前のドワコンの C 問題に似てるということで解いてみました。今回は前回のように二分探索で解くのではなく, ダイクストラっぽく解きたいと思います。

ゴール地点からスタート地点に向かって探索します。ゴール地点からある頂点 (y, x) の距離 d[y][x] がわかっているとすると, (y, x) に隣接する頂点 (ny, nx) について,

・(y, x) から (ny, nx) に普通に行けたらかかるコストは d[y][x] + 1
・(y, x) から (ny, nx) に行けないとすると, 辺 (ny, nx) -> (y, x) は使えないという条件の下での ゴール地点から (ny, nx) への最短距離

となります。最悪の条件では, 上記2つの値の最大値を取れば良いです。これをダイクストラっぽくやります。

const int MAX = 33;
const int INF = 1e9;
bool ok[MAX][MAX][4];
vector<vi> d[MAX][MAX][4];

vector<vi> bfs(int H, int W) {
    vector<vi> d(H, vi(W, INF));
    queue<pii> que;
    que.push(pii(H-1, W-1));
    d[H-1][W-1] = 0;
    while (!que.empty()) {
        auto p = que.front(); que.pop();
        int y = p.first, x = p.second;
        for (int i = 0; i < 4; i++) {
            if (!ok[y][x][i]) continue;
            int ny = y+dy[i], nx = x+dx[i];
            if (d[ny][nx] > d[y][x]+1) {
                d[ny][nx] = d[y][x]+1;
                que.push(pii(ny, nx));
            }
        }
    }
    return d;
}

vector<vi> dijkstra(int H, int W) {
    vector<vi> ret(H, vi(W, INF));
    ret[H-1][W-1] = 0;
    priority_queue<pair<int, pii> > que;
    que.push(make_pair(0, pii(H-1, W-1)));
    while (!que.empty()) {
        auto p = que.top(); que.pop();
        int dist = -p.first;
        int y = p.second.first, x = p.second.second;
        if (dist > ret[y][x]) continue;
        for (int i = 0; i < 4; i++) {
            if (!ok[y][x][i]) continue;
            int ny = y+dy[i], nx = x+dx[i];
            int tmp = max(dist+1, d[y][x][i][ny][nx]);
            if (ret[ny][nx] > tmp) {
                ret[ny][nx] = tmp;
                que.push(make_pair(-ret[ny][nx], pii(ny, nx)));
            }
        }
    }
    return ret;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int H, W;
    while (cin >> H >> W) {
        if (H==0 && W==0) break;
        memset(ok, false, sizeof(ok));
        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W-1; j++) {
                int b;
                cin >> b;
                if (b == 0) {
                    ok[i][j][0] = true;
                    ok[i][j+1][2] = true;
                }
            }
            if (i < H-1) {
                for (int j = 0; j < W; j++) {
                    int b;
                    cin >> b;
                    if (b == 0) {
                        ok[i][j][1] = true;
                        ok[i+1][j][3] = true;
                    }
                }
            }
        }
        vector<vi> d0 = bfs(H, W);
        for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {
            for (int k = 0; k < 4; k++) {
                if (ok[i][j][k]) {
                    ok[i][j][k] = false;
                    d[i][j][k] = bfs(H, W);
                    ok[i][j][k] = true;
                }
            }
        }
        vector<vi> ans = dijkstra(H, W);
        int out = ans[0][0];
        if (out >= INF) out = -1;
        cout << out << endl;
    }
    return 0;
}