J - Fire! UVA - 11624【多源BFS】

J - Fire!

题意:
房间里起火,人和火可以上下左右走,每分钟都走一格(火是四个方向同时一格),都不能越过墙。人只要走到房间边界(非墙)就可以逃生。给定人、火、墙的位置,如果人能逃生,输出所需时间,如果不能,输出IMPOSSIBLE

思路:
对于每个可走格子,算火的最短到达时间和人的最短到达时间,“最短”用BFS达成,先火BFS后人BFS
火的BFS中,由于在每分钟时间内,所有的火都同时扩散,参考《文明》,vector结合queue
在人的BFS中,如果人的下一格子<那个格子的火则可走
原本是全部算完之后再遍历边界,但问题在于算人的时候没有考虑到火已经先到的问题

#include<cstdio>
#include<iostream>
#include<queue>

using namespace std;
struct node {
	int x, y;
};
struct Time {
	int F, J;
};
queue<node> fq;
queue<node> jq;
int m, n;
Time dis[1000 + 10][1000 + 10];
int map[1000 + 10][1000 + 10];
vector<node> v;

void Clear() {//dis初始化
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			dis[i][j].F = -1;
			dis[i][j].J = -1;
		}
	}
}

int dx[] = { 0,-1,1,0,0 };
int dy[] = { 0,0,0,-1,1 };
//上下左右 
void FireBFS() {
	for(int i=0;i<v.size();i++) fq.push(v[i]);
	v.clear();
	
	while (!fq.empty()) {
		node t = fq.front();
		fq.pop();
		for (int i = 1; i <= 4; i++) {
			int nx = t.x + dx[i];
			int ny = t.y + dy[i];
			if (nx<1 || ny<1 || nx>m || ny>n || map[nx][ny] == -1 || dis[nx][ny].F != -1) continue;
			dis[nx][ny].F = dis[t.x][t.y].F + 1;
			node p;
			p.x = nx; p.y = ny;
			v.push_back(p);
		}
	}
}

int JoeBFS() {
	while (!jq.empty()) {
		node t = jq.front();
		jq.pop();
		if(t.x==m||t.x==1||t.y==1||t.y==n) return dis[t.x][t.y].J+1;
		for (int i = 1; i <= 4; i++) {
			int nx = t.x + dx[i];
			int ny = t.y + dy[i];
			//越界或者是墙 
			if (nx<1 || ny<1 || nx>m || ny>n || map[nx][ny] == -1) continue;
			//已经走过 
			if(dis[nx][ny].J != -1) continue;
			//火已经到了
			if(dis[nx][ny].F!=-1&&dis[nx][ny].F<=dis[t.x][t.y].J + 1)continue;
			dis[nx][ny].J = dis[t.x][t.y].J + 1;
			node p;
			p.x=nx;p.y=ny;
			jq.push(p);
		}
	}
	return -1;
}

int  main()
{
	int t;
	cin >> t;
	while (t--) {
		while (!fq.empty()) fq.pop();
		while (!jq.empty()) jq.pop();
		cin >> m >> n;
		node t;
		Clear();
		v.clear();
		for (int i = 1; i <= m; i++) {
			char c = getchar();
			for (int j = 1; j <= n; j++) {
				c = getchar();
				if (c == '#') map[i][j] = -1;
				else if (c == 'F') {
					map[i][j] = -2;
					dis[i][j].F = 0;
					t.x = i; t.y = j;
					v.push_back(t);
				}
				else if (c == 'J') {
					map[i][j] = 1;
					dis[i][j].J = 0;
					t.x = i; t.y = j;
					jq.push(t);
				}
				else map[i][j] = 0;
			}
		}
		while(v.size()) FireBFS();
		int ans=JoeBFS();
		
		if (ans==-1) cout << "IMPOSSIBLE" << endl;
		else cout << ans << endl;
	}
	return 0;
}
!!!!错误代码!!!!
思路是人和火都一步一步走,走法参考《文明》
能过样例,但是WA,原因是忘记倒空队列和vector
但还是TLE了
而且也没考虑多个出口时取最短时间
走出去的边界也没考虑全(忽略了上边和左边)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring> 
#include<vector>
using namespace std;

int m, n;
char map[1000 + 10][1000 + 10];
int dis[1000 + 10][1000 + 10];
struct node {
	int x, y;
};
queue<node> Fq;
queue<node> Jq;
int dx[] = { 0,1,-1,0,0 };
int dy[] = { 0,0,0,1,-1 };
//下,上,右,左 
vector<node> Fv;
vector<node> Jv;

int bfs() {
	for(int i=0;i<Fv.size();i++) Fq.push(Fv[i]);
	Fv.clear();
	for(int i=0;i<Jv.size();i++) Jq.push(Jv[i]);
	Jv.clear();
	//先火后人
	node k;
	
	while(!Fq.empty()){
		node F = Fq.front();
		Fq.pop();
		for (int i = 1; i <= 4; i++) {
			int fx = F.x + dx[i];
			int fy = F.y + dy[i];
			if (fx<1 || fy<1 || fx>m || fy>n || dis[fx][fy] == -1 || dis[fx][fy] == -2) continue;
			dis[fx][fy] = -2;
			k.x = fx;
			k.y = fy;
			Fv.push_back(k);
		}
	}
	
	node J = Jq.front();
	Jq.pop();
	if ((J.x == m || J.y == n) && dis[J.x][J.y] != -1) return -1;//走出去了
	for (int i = 1; i <= 4; i++) {
		int jx = J.x + dx[i];
		int jy = J.y + dy[i];
		if (jx<1 || jy<1 || jx>m || jy>n || dis[jx][jy] != 0) continue;
		k.x = jx;
		k.y = jy;
		Jv.push_back(k);
	}
	if (Jv.size()) return 1;//有路可走
	else return 0;//无路可走 
}

int main()
{
	int t;
	cin >> t;
	while (t--) {
		memset(dis, 0, sizeof(dis));
		Fv.clear();
		Jv.clear();
		while(!Jq.empty()) Jq.pop();
		while(!Fq.empty()) Fq.pop();
		cin >> m >> n;
		for (int i = 1; i <= m; i++) {
			char c = getchar();
			for (int j = 1; j <= n; j++) {
				c = getchar();
				map[i][j]=c;
				node k;
				if (c == '#') dis[i][j] = -1;
				else if (c == 'J') {
					dis[i][j] = 1;
					k.x = i;
					k.y = j;
					Jv.push_back(k);
				}
				else if (c == 'F') {
					dis[i][j] = -2;
					k.x = i;
					k.y = j;
					Fv.push_back(k);
				}
				else dis[i][j] = 0;
			}
		}
		
	/*	cout<<endl;
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++) cout<<map[i][j];
			cout<<endl;
		}
	*/
			 	
		int Result;
		int i;
		for (i = 1;;i++) {
			Result = bfs();
			if (Result==1) continue;
			else break;
		}
		if (!Result) cout << "IMPOSSIBLE" << endl;
		else cout << i << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值