E - Fire! (双向bfs)

UVA-11624-Fire!

 

题意:在n*m的网格内,有一个人和n堆火,人可以往上下左右四个方向走,同时所有的火也会想四周蔓延,问你人可不可以在火包围他之前逃离这个n*m的范围。

思路:问人可不可以逃离这个范围,就是看人能不能走到最外面的一圈的格子。但是人在走的时候火也会走,那么我们就要进行人 和火的同时的bfs,人和火同时bfs同时更新状态,首先对于人,人先往四周bfs,但是问题来了,我们怎么判断什么时候这一轮人的bfs应该停止去进行火的bfs——————我们可以在每次bfs之前去记录队列中包含的元素,只要对队列的元素进行 bfs就可以停止了,之后对火的bfs就可以了。但是有个问题需要注意一下,就是当人的bfs之后,火可能会把人能走的位置直接封住,但是人的可能的情况已经进入队列了,我们再删除也不好处理,那么我们可以逆向思维先bfs火的范围的,因为火如果先走的话那么人直接走能走的点就可以了

那么最后的整体的框架就是:

先bfs火能走的范围

然后bfs人能走的范围

每次bfs的次数是bfs之前队列的元素的个数

注意最后到达最外圈的结果应该要+1才能出去

最后我bfs的标记写错了,我的每次标记时是在出队的时候再标记

但是正确的标记应该是在入队的时候就去标记,因为如果是在出队时才标记,那么可能会标记很多重复的元素导致t(比如我入队了{1,2,3}三个元素,然后到1这个元素的时候也可能会入队{2,3}这两个元素,而先标记1 2 3三个元素在之后就不会出现重复入队的情况),当时就卡了这个点qwq!!!

代码

/**
 *  ┏┓   ┏┓+ +
 * ┏┛┻━━━┛┻┓ + +
 * ┃       ┃
 * ┃   ━   ┃ ++ + + +
 *  ████━████+
 *  ◥██◤ ◥██◤ +
 * ┃   ┻   ┃
 * ┃       ┃ + +
 * ┗━┓   ┏━┛
 *   ┃   ┃ + + + +Code is far away from  
 *   ┃   ┃ + bug with the animal protecting
 *   ┃    ┗━━━┓ 神兽保佑,代码无bug 
 *   ┃  	    ┣┓
 *    ┃        ┏┛
 *     ┗┓┓┏━┳┓┏┛ + + + +
 *    ┃┫┫ ┃┫┫
 *    ┗┻┛ ┗┻┛+ + + +
 */

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <map>
#define sc_int(x) scanf("%d", &x)
#define sc_ll(x) scanf("%lld", &x)
#define pr_ll(x) printf("%lld", x)
#define pr_ll_n(x) printf("%lld\n", x)
#define pr_int_n(x) printf("%d\n", x)
#define ll long long
using namespace std;

const int N = 1000000 + 100;
int n, m, h;
ll s[N];
char Map[1010][1010];

struct lk
{
	int x;
	int y;
	int cnt;
};
queue<lk> q, p;
int dirx[5] = {0, 1, 0, -1, 0};
int diry[5] = {0, 0, -1, 0, 1};
bool st[1010][1010];
bool stf[1010][1010];

void bfs(int a, int b)
{

	q.push({a, b, 0});
	st[a][b] = 1;
	int sum=0;
	while (q.size() )
	{
		while (p.size())
		{

			lk kk = p.front();
				if (kk.cnt > sum)
				break;
			p.pop();
	
			// cout<<kk.x<<"huo"<<kk.y<<endl;
			for (int i = 1; i <= 4; i++)
			{
				int xx = kk.x + dirx[i], yy = kk.y + diry[i];
	
				if (xx < 1 || xx > n || yy < 1 || yy > m)
					continue;
				if ( Map[xx][yy] != '.')
					continue;
					// cout<<xx<<" "<<yy<<endl;
				Map[xx][yy]='F';
				p.push({xx, yy, kk.cnt + 1});
			}
		}

		while (q.size())
		{
			lk k = q.front();
			if(k.cnt>sum)break;
			q.pop();

			// cout<<k.x<<" ren "<<k.y<<endl;
			if (k.x == 1 || k.x == n || k.y == 1 || k.y == m)
			{
				cout << k.cnt+1 << endl;
				return;
			}			


			for (int i = 1; i <= 4; i++)
			{
				int xx = k.x + dirx[i], yy = k.y + diry[i];
				if (xx < 1 || xx > n || yy < 1 || yy > m)
					continue;
				if (st[xx][yy] || Map[xx][yy] == '#'||Map[xx][yy]=='F')
					continue;
				st[xx][yy] = 1;					
				q.push({xx, yy, k.cnt + 1});
			}
		}

		sum++;
	}

	cout << "IMPOSSIBLE\n";
	return;
}

int main()
{
	int t;
	sc_int(t);
	while (t--)
	{	
		memset(st,0,sizeof st);

		while(q.size())q.pop();
		while(p.size())p.pop();
		int x, y;
		cin >> n >> m;
		for (int i = 1; i <= n; i++)
			cin >> Map[i] + 1;
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				if (Map[i][j] == 'F')
				{
					p.push({i, j, 0});
					stf[i][j] = 1;
				}
				if (Map[i][j] == 'J')
				{
					x = i;
					y = j;
				}
			}
		}
		bfs(x, y);
	}

	return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值