2020CCPC威海/gym102798 B-Labyrinth
题意
给定一个(n)行(m)列的格点图,图中有(k)个黑洞,有(q)次询问,每次询问给出入口((xs,ys))和出口((xt,yt)),问从入口走到出口的最短距离,若无法到达输出(-1),最短距离为走的步数,每一步可以选择上下左右四个方向走。
(1le n,m le 2cdot 10^5,nmle 2cdot 10^5,0le k le 42)
分析
分类讨论一下:
- 若以入口和出口为顶点构成的矩形中没有黑洞,那么答案即为两点的曼哈顿距离。
- 若以入口和出口为顶点构成的矩形中有黑洞且存在入口到出口的路径,那么一定存在一条最短路是经过某个黑洞旁边可以走的格点的。
我们可以把所有黑洞旁边的格点作为起点bfs求最短路,然后更新(ans=min(ans,dis[xs][ys]+dis[xt][yt]))。
Code
#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=2e5+10;
const int inf=1e9;
int n,m,k,q;
int xx[]={1,-1,0,0};
int yy[]={0,0,1,-1};
vector<vector<int> >a,b,dis[210];
vector<pii>v;
bool ck(int x,int y){
return x>=1&&x<=n&&y>=1&&y<=m;
}
int cal(int x1,int y1,int x2,int y2){
if(x1>x2) swap(x1,x2);
if(y1>y2) swap(y1,y2);
return b[x2][y2]-b[x1-1][y2]-b[x2][y1-1]+b[x1-1][y1-1];
}
void bfs(int it,pii s){
queue<pii>q;
dis[it][s.fi][s.se]=0;
q.push(s);
while(!q.empty()){
pii u=q.front();q.pop();
for(int i=0;i<4;i++){
int dx=u.fi+xx[i];
int dy=u.se+yy[i];
if(ck(dx,dy)&&!a[dx][dy]&&dis[it][u.fi][u.se]+1<dis[it][dx][dy]){
dis[it][dx][dy]=dis[it][u.fi][u.se]+1;
q.push(mp(dx,dy));
}
}
}
}
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
scanf("%d%d%d%d",&n,&m,&k,&q);
a.resize(n+5,vector<int>(m+5,0));
b.resize(n+5,vector<int>(m+5,0));
vector<pii>hole;
for(int i=1,x,y;i<=k;i++){
scanf("%d%d",&x,&y);
a[x][y]=b[x][y]=1;
hole.pb(mp(x,y));
}
for(pii it:hole){
for(int i=0;i<4;i++){
int dx=it.fi+xx[i];
int dy=it.se+yy[i];
if(ck(dx,dy)&&!a[dx][dy]) v.pb(mp(dx,dy));
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
b[i][j]+=b[i][j-1]+b[i-1][j]-b[i-1][j-1];
}
}
for(int i=0;i<sz(v);i++){
dis[i].resize(n+5,vector<int>(m+5,inf));
bfs(i,v[i]);
}
while(q--){
int xs,ys,xt,yt;
scanf("%d%d%d%d",&xs,&ys,&xt,&yt);
if(cal(xs,ys,xt,yt)==0){
if(xs>xt) swap(xs,xt);
if(ys>yt) swap(ys,yt);
printf("%d
",xt-xs+yt-ys);
}else{
int ans=inf;
for(int i=0;i<sz(v);i++){
ans=min(ans,dis[i][xs][ys]+dis[i][xt][yt]);
}
if(ans==inf) ans=-1;
printf("%d
",ans);
}
}
return 0;
}