Codeforces 1301F Super Jaber
题目链接
https://codeforces.com/contest/1301/problem/F
题目大意
一个 $n \times m$ 的网格,每个格子有一个颜色,颜色的总数不超过 $40$ 个。从一个格子出发可以花 $1$ 单位的时间到达与它有边相邻的格子或者颜色相同的格子。 $q$ 次询问,每次询问两个格子之间的最短路。
题目分析
如果询问的两点的最短路径使用了颜色跳跃的话,那么显然答案可以表示为两个点分别到达该颜色的最短路加 $1$。如果不跳跃的话显然答案是两个格子之间的曼哈顿距离。那么可以用 $BFS$ 求出所有的点到达某种颜色的最小值,即可解决这道题。
代码
#include <bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; int dis[1005][1005][45]; int a[1005][1005]; bool v[45][45]; struct ex { int x, y, z; }; vector <ex> vec[45]; queue <ex> q; int dx[] = {0, 1, 0, -1}; int dy[] = {1, 0, -1, 0}; int n, m, k, t; int main(){ int i, j; scanf("%d%d%d", &n, &m, &k); memset(dis, 0x3f3f3f3f, sizeof(dis)); for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ scanf("%d", &a[i][j]); vec[a[i][j]].push_back({i, j}); } } for(i=1;i<=k;i++) v[i][i] = true; for(int z=1;z<=k;z++){ for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ if(a[i][j] == z){ dis[i][j][z] = 0; q.push({i, j}); } } } while(q.size()){ int x = q.front().x, y = q.front().y; q.pop(); for(i=0;i<4;i++){ if(1 <= x + dx[i] and x + dx[i] <= n and 1 <= y + dy[i] and y + dy[i] <= m){ if(dis[x + dx[i]][y + dy[i]][z] > dis[x][y][z] + 1){ dis[x + dx[i]][y + dy[i]][z] = dis[x][y][z] + 1; q.push({x + dx[i], y + dy[i], z}); } } } if(!v[z][a[x][y]]){ v[z][a[x][y]] = true; for(auto tmp : vec[a[x][y]]){ if(dis[tmp.x][tmp.y][z] > dis[x][y][z] + 1){ dis[tmp.x][tmp.y][z] = dis[x][y][z] + 1; q.push({tmp.x, tmp.y, z}); } } } } } scanf("%d", &t); while(t--){ int x, y, a, b; scanf("%d%d%d%d", &x, &y, &a, &b); int ans = abs(x - a) + abs(y - b); for(i=1;i<=k;i++){ ans = min(ans, dis[x][y][i] + dis[a][b][i] + 1); } printf("%d\n", ans); } return 0; }