W
H
X

CF1301F Super Jaber

题面

最终答案的方案可以分为2种:1、不使用传送 2、从起点s到最近(步数最少)的颜色为c的格子x,传送到离终点t最近的颜色也为c的格子y,再走到t(从s到x,y到t的过程中均可使用传送)

询问次数多,如果预处理出f[k][i][j]表示从格子(i, j)到一个颜色为k的格子的最少步数,询问时只要枚举中间格子的颜色取最小值即可得出答案

关键在于预处理的方法喽

把每种颜色分开处理(对f数组的每个k处理一遍),如果在上述过程中,从s到x,y到t的过程中不能使用传送,普通的多源bfs即可解决问题

处理中间过程的传送方法也简单:对于每一种颜色color,多源bfs的过程中第一次走到颜色为color的格子上时,将所有颜色为color且未被访问的格子都放入队列

每次多源bfs中每个格子只访问一遍,复杂度O(n),预处理总复杂度O(nk),询问复杂度O(mk),总复杂度O((n+m)k)

#include <bits/stdc++.h>
using namespace std;
inline void read (int &x) {
    char ch = getchar(); x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
} const int N = 1024, K = 50;
int n, m, k, a[N][N], f[K][N][N];
int sx[4] = {0, 1, 0, -1}, sy[4] = {1, 0, -1, 0};
vector <pair<int, int> > v[K];
queue <pair<int, int> > que[K]; int used[K], vis[N][N];
inline void work (int p) {
    for (int i = 1; i <= k; ++i) used[i] = 0;
    while (que[p].size()) {
        int x = que[p].front().first, y = que[p].front().second;
        for (int i = 0; i < 4; ++i) {
            int tx = x + sx[i], ty = y + sy[i];;
            if (tx < 1 || ty < 1 || tx > n || ty > m || f[p][tx][ty]) continue;
            f[p][tx][ty] = f[p][x][y] + 1; que[p].push (make_pair (tx, ty));
        } if (!used[a[x][y]]) {
            used[a[x][y]] = 1;
            for (int i = 0; i < v[a[x][y]].size(); ++i) {
                int tx = v[a[x][y]][i].first, ty = v[a[x][y]][i].second;
                if (!f[p][tx][ty]) f[p][tx][ty] = f[p][x][y] + 1, que[p].push (make_pair (tx, ty));
            }
        } que[p].pop();
    }
}
#define Min(x, y) (x > y ? y : x)
signed main() {
    read (n), read (m), read (k);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            read (a[i][j]), f[a[i][j]][i][j] = 1;
            v[a[i][j]].push_back (make_pair (i, j)), que[a[i][j]].push (make_pair (i, j));
        }
    for (int i = 1; i <= 40; ++i) work (i);
    int T, xi, yi, xj, yj; read (T);
    while (T--) {
        read (xi), read (yi), read (xj), read (yj);
        int res = abs (xi - xj) + abs (yi - yj);
        for (int i = 1; i <= k; ++i) res = Min (res, f[i][xi][yi] + f[i][xj][yj] - 1);
        printf ("%d\n", res);
    } return 0;
}
posted @ 2020-04-10 17:08  -敲键盘的猫-  阅读(214)  评论(0编辑  收藏  举报