CCPC2020Weihai B. Labyrinth

Labyrinth

题目描述

n ∗ m n*m nm网格图,上面有 k k k个黑洞,有 q ≤ 1 e 5 q \leq 1e5 q1e5个询问,每次问从一个点走到另一个点不能走黑洞的最短距离是多少。

思路

绝大多数情况下都是曼哈顿距离,只有当黑洞影响到正常的曼哈顿距离的时候才会考虑黑洞的存在,然后就判定有没有黑洞在矩形框里面即可。

当没有黑洞在里面的时候,直接输出曼哈顿距离。

当有黑洞在里面的时候,肯定最优方案蹭了黑洞的边。

  • 那么就有聪明的小伙伴会问了,为啥啊?

因为黑洞如果没有阻碍正常的曼哈顿距离,那么一定有一种方案是贴着黑洞边走的。

如果黑洞阻碍了曼哈顿距离,那么一定得蹭着某个黑洞的边缘才能达到最小的距离代价。

正好黑洞数目也不多,格点数目也不多,能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;
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 点我我会动 设计师:白松林 返回首页