Labyrinth
题目描述
n ∗ m n*m n∗m网格图,上面有 k k k个黑洞,有 q ≤ 1 e 5 q \leq 1e5 q≤1e5个询问,每次问从一个点走到另一个点不能走黑洞的最短距离是多少。
思路
绝大多数情况下都是曼哈顿距离,只有当黑洞影响到正常的曼哈顿距离的时候才会考虑黑洞的存在,然后就判定有没有黑洞在矩形框里面即可。
当没有黑洞在里面的时候,直接输出曼哈顿距离。
当有黑洞在里面的时候,肯定最优方案蹭了黑洞的边。
- 那么就有聪明的小伙伴会问了,为啥啊?
因为黑洞如果没有阻碍正常的曼哈顿距离,那么一定有一种方案是贴着黑洞边走的。
如果黑洞阻碍了曼哈顿距离,那么一定得蹭着某个黑洞的边缘才能达到最小的距离代价。
正好黑洞数目也不多,格点数目也不多,能BFS+存下黑洞格点到其他所有点的距离
所以针对有黑洞在里面的时候,枚举蹭了哪个边就可以了。
代码
#include<bits/stdc++.h>
using namespace std;
const int K = 47, NM = 200017;
const unsigned long long INF = 2e10;
struct Point{int x,y;}Black[K];
int n, m, k, q, dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
long long pos[K<<2], dis[K<<2][NM];
set<unsigned long long>blacks;
unsigned long long GETINDEX(int x, int y){
return 1ll * (x-1) * m + (y-1);
}
void BFS(int p,unsigned long long nowpos){
for(int i=0;i<NM;++i) dis[p][i]=INF;
if(blacks.find(nowpos) != blacks.end()) return;//if not write, WA on test12
queue<unsigned long long>qu;
qu.push(nowpos); dis[p][nowpos] = 0;
while(!qu.empty()){
unsigned long long deal = qu.front();
qu.pop(); int x = deal / m + 1, y = deal % m + 1;
for(int i=0, nx, ny;i<4;++i){
nx = x + dx[i]; ny = y + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > m) continue;
unsigned long long NEWINDEX = GETINDEX(nx, ny);
if(blacks.find(NEWINDEX) != blacks.end()) continue;
if(dis[p][NEWINDEX] == INF){
dis[p][NEWINDEX] = dis[p][deal] + 1;
qu.push(NEWINDEX);
}
}
}
}
bool Insert(int tx, int ty, int sx, int sy, int ex, int ey){
if(sx > ex) swap(sx, ex); if(sy > ey) swap(sy, ey);
if(tx >= sx && tx <= ex && ty >= sy && ty <= ey) return 1;
return 0;
}
int main(){
scanf("%d%d%d%d", &n,&m,&k,&q);
for(int i=1;i<=k;++i){
scanf("%d%d", &Black[i].x, &Black[i].y);
blacks.insert(GETINDEX(Black[i].x, Black[i].y));
for(int j=0;j<4;++j){
unsigned long long newpos;
newpos = GETINDEX(Black[i].x+dx[j], Black[i].y+dy[j]);
pos[i*4-4+j]=newpos;
}
}
for(int i=0;i<4*k;++i)
BFS(i, pos[i]);
for(int i=1,sx,sy,ex,ey;i<=q;++i){
scanf("%d%d%d%d", &sx,&sy,&ex,&ey);
long long distance = 5 * INF;
unsigned long long cs = GETINDEX(sx, sy), ce = GETINDEX(ex, ey);
if(blacks.find(cs) != blacks.end() || blacks.find(ce) != blacks.end()){
printf("-1\n");continue;
}
for(int j=1;j<=k;++j){
if(!Insert(Black[j].x, Black[j].y, sx, sy, ex, ey))
continue;
for(int p=0;p<4;++p)
distance = min(distance, dis[4*j-4+p][cs] + dis[4*j-4+p][ce]);
}
if(distance == 5 * INF)
distance = abs(sx-ex) + abs(sy-ey);
else if(distance >= INF)
distance = -1;
printf("%lld\n", distance);
}
return 0;
}