Codeforces Round #619 (Div. 2) F

题意

n m n*m 的格子,每个格子有个颜色,相同颜色可以直接到达或者走相邻格子,多个询问求两点间最短距离。

题解

首先我们容易想到求两个颜色之间的距离,但是这样子不好维护。
因为不确定答案是 d i s + 1 dis+1 还是 d i s + 2 dis+2 还是 d i s dis
我们多加一层信息,卡内存维护了一个颜色到所有点最短距离。
这个可以用多源 b f s bfs 维护,每到达一个新颜色,就把同一颜色所有点更新。
并且根据 b f s bfs 的性质,第一次到达的距离一定是最小的,所以之后不用再更新这一颜色。

求出来之后我们还是不确定是 d i s + 1 dis+1 还是 d i s dis
如果不使用颜色跨越,答案就是曼哈顿距离。
如果使用的话,我们考虑枚举哪个颜色用了跨越,然后答案是 d i s [ i ] [ l ] + d i s [ i ] [ r ] + 1 dis[i][l]+dis[i][r]+1
表示 i i 颜色到左点和到右点的距离加上跨越的贡献。

取最小即是答案,因为最短路是相互的所以这样求是可以的。

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

发布了203 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/mxYlulu/article/details/104325081