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;
}