血色先锋队~带有技巧的广搜

题目描述

在这里插入图片描述

输入样例

5 4 2 3
1 1
5 4
3 3
5 3
2 4

输出样例

3
1
3

AC Code

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const ll Lim = 100005;
const int maxn = 505;
struct xy{
	int x,y,s;
};
bool vis[maxn][maxn];
int s[maxn][maxn] = {0};
int xe[Lim][2] = {0};
int n,m,a,b;
queue<xy> q;
void pusher(int x,int y){
	xy t;
	t.x = x,t.y = y,t.s = 0;
	q.push(t);
	vis[x][y] = true;
}
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
void bfs(){
	xy t;
	while(!q.empty()){
		t = q.front();q.pop();
		for(int i=0;i<4;i++){
			int nx = t.x + dx[i],ny = t.y + dy[i];
			if((nx>=1&&nx<=n)&&(ny>=1&&ny<=m)&&!vis[nx][ny]){
				xy t1;
				t1.x = nx,t1.y = ny,t1.s = t.s + 1;
				q.push(t1);
				
				s[nx][ny] = t1.s;
				vis[nx][ny] = true;
			}
		}
	}
}
int main()
{
	memset(vis,false,sizeof(vis));
	cin>>n>>m>>a>>b;
	for(int i=1;i<=a;i++){
		int x,y;
		cin>>x>>y;
		pusher(x,y);
	}
	for(int i=1;i<=b;i++){
		cin>>xe[i][0]>>xe[i][1];
	}
	bfs();
	for(int i=1;i<=b;i++){
		cout<<s[xe[i][0]][xe[i][1]]<<endl;
	}
	return 0;
}

解释

〇本题思路来源于洛谷博主 sinsop90
①从题意可以看出,本题的起点具有多个,并且需要同时移动。一开始我的思路是,让他们一个个通过广搜向外扩散,某点的权值(感染时间)取最小值,但很快会发现这样的答案会使所有测试点TLE,那么如何解决同时移动的问题呢?其实很简单,通过一个布尔数组vis记录某点是否已经经过,且所有初始起点在输入时同时入列即可实现。 可以想象,倘若初始起点全部入列,那么每次bfs()操作之后,该点的下几个结点进入队尾,而对头的下一个点正是另一个初始起点,再加上vis数组判断某点是否经过,可以轻松模拟多个起始端点的同时移动。
pusher()函数用于将初始起点入队,不再赘述,主要展示一下bfs()广搜函数的细节:

void bfs(){
	xy t;
	while(!q.empty()){
		t = q.front();q.pop();
		for(int i=0;i<4;i++){
			int nx = t.x + dx[i],ny = t.y + dy[i];
			if((nx>=1&&nx<=n)&&(ny>=1&&ny<=m)&&!vis[nx][ny]){
				xy t1;
				t1.x = nx,t1.y = ny,t1.s = t.s + 1;
				q.push(t1);
				
				s[nx][ny] = t1.s;
				vis[nx][ny] = true;
			}
		}
	}
}

👆可以注意到,此处的bfs()和先前的广搜不同,使广搜停止的条件与图遍历相同,那就是队空。注意,一定不要在while循环内部先判断该点是否已经经过,因为一开始在pusher()中已经设置初始起点为经过。
③AC。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值