【SSL 1823】消灭怪物(非传统BFS)

钟鼎山林无非幻境,静中岁月自有长春 / 2024-11-13 / 原文

题目大意

小b现在玩一个极其无聊的游戏,它控制角色从基地出发,一路狂奔夺走了对方的水晶,可是正准备回城时,发现地图上已经生成了n 个怪。

现在假设地图是二维平面,所有的怪和角色都认为是在这个二维平面的点上。请你帮小b计算一下,从现在角色的位置开始,至少要消灭几个怪才能回到基地(坐标原点)。

注意:小b控制的角色只能沿平行于坐标轴的方向移动(东、西、南、北),而且每次必须移动整数距离。
数据范围
1≤n≤50000
1≤x,y≤1000

输入格式

第一行包含三个整数:n 以及角色的初始位置 (x,y) 。

接下来 n 行,每行包含一个怪的位置坐标 (x,y)。

输出格式

一个数,表示最少要消灭的怪的个数。

输入样例

7 6 3
6 2
5 2
4 3
2 1
7 3
5 4
6 4

输出样例

1

基本思路

知道起点和终点,每次扩展一步,题目具有 bfs 的特征。

但是单纯 bfs 它只会管几层,而不会处理路过怪物数量。但题目要求最少经过怪物,所以绕路是十分必要的,而普通 bfs 中可能会让有怪物的点优先扩展,而违背了这个原则。
image

所以我们要介绍一个新东西,双端队列deque。顾名思义,就是队首队尾都可以进出元素。所以我们可以让无怪物的点从队头进,有怪物的点从队尾进,取的时候仍是从队头取。这样就可以尽可能绕开怪物,而不会让不得不消灭的怪物被排除。

核心代码

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=1e3+10;
struct node{
	int x,y,cnt;
};
int n,sx,sy,w[4][2]={{0,1},{1,0},{0,-1},{-1,0}},ans=0x3f3f3f3f;
bool v[N][N],a[N][N];
deque<node>q;
inline int bfs(){
	q.push_back({sx,sy,0});
	v[sx][sy]=true;
	while(!q.empty()){
		node u=q.front();
		q.pop_front();
		if(u.x==0&&u.y==0)
			return u.cnt;//到达终点
		for(int i=0;i<4;i++){
			int xx=u.x+w[i][0],yy=u.y+w[i][1];
			if(xx<0||xx>=N||yy<0||yy>=N) continue;
			if(v[xx][yy]==true) continue;
			if(a[xx][yy]==true)
				q.push_back({xx,yy,u.cnt+1});
			else
				q.push_front({xx,yy,u.cnt});
			v[xx][yy]=true;
		}
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>sx>>sy;
	for(int i=1,x,y;i<=n;i++){
		cin>>x>>y;
		a[x][y]=true;
	}
	cout<<bfs();
	return 0;
}