题解:P13654 [CERC 2020] Excavation

· · 题解

Prepare

深度优先搜索。

Solution

五种类型的挖掘机不重要,只是相当于五种移动方式而已,本质是一样的。

注意到任意两点间都有双向边,所以本质是一张无向图,每次可以将一条边缩成一个点,求能否将图缩成一个点。

由于是无向图,所以只要这张图连通就一定能缩成一个点,缩成哪个点不重要。我们取任意一个点为最终剩下的点,通过搜索向外扩展并记录路径,只要发现可达点就朝可达点搜索,最后判断一下是否还有未搜索到的点,若有则说明图不连通,无解,否则反向输出路径。反向输出是因为我们刚才是倒推着遍历的。

Code

#include <bits/stdc++.h>

using namespace std;

const long long N = 105, inf = 4e18, mod = 998244353;

long long n, cnt = 0, sx, sy;

struct res {
    long long sx, sy, tx, ty;
} ans[N * N];

bool vis[N][N];

char ty, ch;

inline long long read() {
    long long x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - 48;
        ch = getchar();
    }
    return x * f;
}

void dfs(long long x, long long y, long long nx, long long ny) {
    vis[x][y] = 0;
    ans[++cnt] = res{x, y, nx, ny};
    if (ty == 'R') {
        for (long long i = 1; i <= n; ++i) {
            if (x - i >= 1 && vis[x - i][y]) {
                dfs(x - i, y, x, y);
            }
            if (x + i <= n && vis[x + i][y]) {
                dfs(x + i, y, x, y);
            }
            if (y - i >= 1 && vis[x][y - i]) {
                dfs(x, y - i, x, y);
            }
            if (y + i <= n && vis[x][y + i]) {
                dfs(x, y + i, x, y);
            }
        }
    }
    if (ty == 'Q') {
        for (long long i = 1; i <= n; ++i) {
            if (x - i >= 1 && vis[x - i][y]) {
                dfs(x - i, y, x, y);
            }
            if (x + i <= n && vis[x + i][y]) {
                dfs(x + i, y, x, y);
            }
            if (y - i >= 1 && vis[x][y - i]) {
                dfs(x, y - i, x, y);
            }
            if (y + i <= n && vis[x][y + i]) {
                dfs(x, y + i, x, y);
            }
            if (x - i >= 1 && y - i >= 1 && vis[x - i][y - i]) {
                dfs(x - i, y - i, x, y);
            }
            if (x - i >= 1 && y + i <= n && vis[x - i][y + i]) {
                dfs(x - i, y + i, x, y);
            }
            if (x + i <= n && y - i >= 1 && vis[x + i][y - i]) {
                dfs(x + i, y - i, x, y);
            }
            if (x + i <= n && y + i <= n && vis[x + i][y + i]) {
                dfs(x + i, y + i, x, y);
            }
        }
    }
    if (ty == 'B') {
        for (long long i = 1; i <= n; ++i) {
            if (x - i >= 1 && y - i >= 1 && vis[x - i][y - i]) {
                dfs(x - i, y - i, x, y);
            }
            if (x - i >= 1 && y + i <= n && vis[x - i][y + i]) {
                dfs(x - i, y + i, x, y);
            }
            if (x + i <= n && y - i >= 1 && vis[x + i][y - i]) {
                dfs(x + i, y - i, x, y);
            }
            if (x + i <= n && y + i <= n && vis[x + i][y + i]) {
                dfs(x + i, y + i, x, y);
            }
        }
    }
    if (ty == 'N') {
        if (x >= 3 && y >= 2 && vis[x - 2][y - 1]) {
            dfs(x - 2, y - 1, x, y);
        }
        if (x >= 3 && y < n && vis[x - 2][y + 1]) {
            dfs(x - 2, y + 1, x, y);
        }
        if (x >= 2 && y >= 3 && vis[x - 1][y - 2]) {
            dfs(x - 1, y - 2, x, y);
        }
        if (x >= 2 && y < n - 1 && vis[x - 1][y + 2]) {
            dfs(x - 1, y + 2, x, y);
        }
        if (x < n && y >= 3 && vis[x + 1][y - 2]) {
            dfs(x + 1, y - 2, x, y);
        }
        if (x < n && y < n - 1 && vis[x + 1][y + 2]) {
            dfs(x + 1, y + 2, x, y);
        }
        if (x < n - 1 && y >= 2 && vis[x + 2][y - 1]) {
            dfs(x + 2, y - 1, x, y);
        }
        if (x < n - 1 && y < n && vis[x + 2][y + 1]) {
            dfs(x + 2, y + 1, x, y);
        }
    }
    if (ty == 'K') {
        if (x > 1 && vis[x - 1][y]) {
            dfs(x - 1, y, x, y);
        }
        if (x < n && vis[x + 1][y]) {
            dfs(x + 1, y, x, y);
        }
        if (y > 1 && vis[x][y - 1]) {
            dfs(x, y - 1, x, y);
        }
        if (y < n && vis[x][y + 1]) {
            dfs(x, y + 1, x, y);
        }
        if (x > 1 && y > 1 && vis[x - 1][y - 1]) {
            dfs(x - 1, y - 1, x, y);
        }
        if (x > 1 && y < n && vis[x - 1][y + 1]) {
            dfs(x - 1, y + 1, x, y);
        }
        if (x < n && y > 1 && vis[x + 1][y - 1]) {
            dfs(x + 1, y - 1, x, y);
        }
        if (x < n && y < n && vis[x + 1][y + 1]) {
            dfs(x + 1, y + 1, x, y);
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n;
    cin >> ty;
    for (long long i = 1; i <= n; ++i) {
        for (long long j = 1; j <= n; ++j) {
            cin >> ch;
            if (ch == ty) {
                vis[i][j] = 1;
                if (sx == 0 && sy == 0) {
                    sx = i, sy = j; // 取第一个见到的点作为最终剩下的点
                }
            }
        }
    }
//  cout << sx << ' ' << sy << '\n';
    dfs(sx, sy, 0, 0);
    for (long long i = 1; i <= n; ++i) {
        for (long long j = 1; j <= n; ++j) {
            if (vis[i][j]) {
                cout << "NO\n";
                return 0;
            }
        }
    }
    cout << "YES\n";
    for (long long k = cnt; k > 1; --k) {
        cout << ans[k].sx << ' ' << ans[k].sy << ' ' << ans[k].tx << ' ' << ans[k].ty << '\n';
    }
    return 0;
}

/*出题人设置五种移动方式的意义是什么,考验选手码力吗?我都不敢想象写错一个方式调试该有多折磨。一道绿题整出将近200行是何意味,不知道的以为我写平衡树呢。*/