题意
n ∗ m n*m n∗m的地图上,每个格子有一个颜色。最多 k k k种颜色。每次可以花费 1 1 1时间去相邻格子,或者花费 1 1 1时间跳到相同颜色格子。 Q Q Q次查询 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x1,y1), (x2,y2) (x1,y1),(x2,y2)问从 ( x 1 , y 1 ) (x1,y1) (x1,y1)到 ( x 2 , y 2 ) (x2,y2) (x2,y2)最少时间为多少。
n , m ≤ 1000 , Q ≤ 1 e 5 , k ≤ 40 n,m\le 1000,Q\le 1e5,k\le 40 n,m≤1000,Q≤1e5,k≤40
解题思路
从起点到终点,两种可能:
- 没有跳。答案为曼哈顿距离。
- 跳了。枚举跳的颜色。需要知道从当前点到指定颜色最少花费。
现在要求从某个点到指定颜色的最小花费。因为是无向图,所以可以预处理每个颜色到所有点的最小花费。这里使用0-1 BFS一直TLE。其实只用简单BFS就可以了,到达某个没去过的颜色,就把所有同色的没去过的颜色染色。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define fors(i, a, b) for(int i = (a); i < (b); ++i)
#define P pair<int,int>
using namespace std;
int n, m, k;
void read(int &x){
char ch = getchar(); x = 0;
while(ch < '0' || ch > '9') ch = getchar();
while(ch <= '9' && ch >= '0') x = (x<<3)+(x<<1)+(ch^'0'), ch = getchar();
return;
}
bool in(int x, int y){
if(x < 0 || x >= n || y < 0 || y >= m) return false;
return true;
}
const int maxn = 1e6 + 42;
int dis[40][maxn];
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
vector<int> g[maxn], o[40];
queue<int> q;
int col[40], a[maxn];
void bfs(int st, int *vis){
memset(col, 0, sizeof col);
col[st] = 1;
for(int v: o[st]) vis[v] = 1, q.push(v);
while(q.size()){
int u = q.front(); q.pop();
if(!col[a[u]]){
col[a[u]] = 1;
for(int v: o[a[u]]) if(!vis[v]) vis[v] = vis[u]+1, q.push(v);
}
for(int v: g[u]) if(!vis[v]) vis[v] = vis[u]+1, q.push(v);
}
}
void init(){
scanf("%d%d%d", &n, &m, &k);
fors(i, 0, n*m){
int c; read(c); a[i] = c-1;
int x = i/m, y = i%m;
fors(j, 0, 4){
if(in(x+dx[j], y+dy[j])){
int p = (x+dx[j])*m+y+dy[j];
g[i].pb(p);
}
}
o[c-1].pb(i);
}
fors(i, 0, k) bfs(i, dis[i]);
}
void sol(){
int Q; cin>>Q;
while(Q--){
int x1, y1, x2, y2;
read(x1); read(y1); read(x2); read(y2);
x1--; y1--; x2--; y2--;
int ans = abs(x2-x1)+abs(y2-y1);
int p1 = x1*m+y1, p2 = x2*m+y2;
fors(i, 0, k){
if(!dis[i][p1]) continue;
ans = min(dis[i][p1]+dis[i][p2]-1, ans);
}printf("%d\n", ans);
}
}
int main()
{
init(); sol();
}