题意
的格子,每个格子有个颜色,相同颜色可以直接到达或者走相邻格子,多个询问求两点间最短距离。
题解
首先我们容易想到求两个颜色之间的距离,但是这样子不好维护。
因为不确定答案是
还是
还是
我们多加一层信息,卡内存维护了一个颜色到所有点最短距离。
这个可以用多源
维护,每到达一个新颜色,就把同一颜色所有点更新。
并且根据
的性质,第一次到达的距离一定是最小的,所以之后不用再更新这一颜色。
求出来之后我们还是不确定是
还是
。
如果不使用颜色跨越,答案就是曼哈顿距离。
如果使用的话,我们考虑枚举哪个颜色用了跨越,然后答案是
表示
颜色到左点和到右点的距离加上跨越的贡献。
取最小即是答案,因为最短路是相互的所以这样求是可以的。
#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define sf(x) scanf("%d",&x)
typedef long long ll;
using namespace std;
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const int maxk = 40+2;
const int maxn = 1000+2;
int n,m,k;
int dp[maxk][maxn][maxn];
int col[maxn][maxn],vis[maxn][maxn],flag[maxn];
vector<pair<int,int> >G[maxk];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,1,-1};
void bfs(int c){
queue<pair<pair<int,int>,int> >q;
for(auto x:G[c])q.push(make_pair(make_pair(x.first,x.second),0));
memset(vis,0,sizeof(vis));
memset(flag,0,sizeof(flag));
memset(dp[c],0x3f,sizeof(dp[c]));
while(!q.empty()){
int nowx=q.front().first.first,nowy=q.front().first.second,val=q.front().second;q.pop();
if(vis[nowx][nowy])continue;vis[nowx][nowy]=true;
dp[c][nowx][nowy]=val;
if(!flag[col[nowx][nowy]]){
flag[col[nowx][nowy]]=true;
for(auto v:G[col[nowx][nowy]]){
q.push(make_pair(make_pair(v.first,v.second),val+1));
}
}
for(int i=0;i<4;i++){
int x=nowx+dx[i],y=nowy+dy[i];
if(x<1||x>n||y<1||y>m)continue;
if(vis[x][y])continue;
q.push(make_pair(make_pair(x,y),val+1));
}
}
}
int main(){
cin>>n>>m>>k;
FOR(i,1,n)FOR(j,1,m)scanf("%d",&col[i][j]),G[col[i][j]].push_back(make_pair(i,j));
FOR(i,1,k)bfs(i);
int q;cin>>q;
while(q--){
int r1,c1,r2,c2;scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
if(r1==r2&&c1==c2)puts("0");
else if(col[r1][c1]==col[r2][c2])puts("1");
else{
int ans=abs(r1-r2)+abs(c1-c2);
for(int i=1;i<=k;i++)ans=min(ans,dp[i][r1][c1]+dp[i][r2][c2]+1);
printf("%d\n",ans);
}
}
}