1. 程式人生 > >UVA 11624 Fire! (技巧BFS)

UVA 11624 Fire! (技巧BFS)

題意:一個地圖中有空地有牆,空地可以走。地圖中有兩中物品,一種是人,每分鐘可以上下左右任走一格,一種是火,每分鐘會向上下左右一起擴散。問人是否可以逃脫迷宮。逃脫迷宮的條件是到達邊緣。

題解:我的思路比較奇特,我把火和人放在一個佇列中處理了。這種處理方式是先處理火,然後再處理人。為什麼這樣是對的呢如下圖:

就是佇列中一定是一段人,然後一段火,這樣保證人和火是同事進行的。單必須先把火比人先放進佇列中,這樣才能保證人不會走到火將要燒到的位置。如下圖

若人先走的火,人會向左走,但是火也會向右走,意味著火和人會走到一個格子裡。這是會燒死人的。

具體程式碼細節看註釋。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 1010;
char map[maxn][maxn];  // 地圖 
int book[maxn][maxn]; // 標記陣列,記錄這點火或者人是否走過 

struct node{
	int x;   //座標x 
	int y;   // 座標y 
	int step;  // 人的步數 
	int kind;  // 用來區分是人還是火,1是人,0是火 
};
queue<node> q;
int n,m,ans;  // n,m表示長寬。ans表示火的個數 
node ren;   //記錄人的起始位置 
node fire[maxn];  // 記錄火的起始位置 
int mov[4][2] = {1,0,-1,0,0,1,0,-1};  // 移動陣列 
void bfs(){
	node now,next;
	for(int i = 0 ; i < ans ; i++){  // 先把火入佇列 
		q.push(fire[i]);
	}
	q.push(ren);   // 再把人放入佇列 
//	cout<<ren.step<<endl;
	while(!q.empty()){
		now = q.front();
		q.pop();
		if(now.kind == 1 && (now.x == 0 || now.y== 0 || now.x == n-1 ||now.y == m-1)){   // 當是人到達邊緣時 
			cout << now.step+1 << endl;
			return ;
		}
		for(int i = 0 ; i < 4 ; i++){  // 對火對人進行移動 
			next.x = now.x+mov[i][0];
			next.y = now.y+mov[i][1];
			if(next.x < 0 || next.x >= n || next.y < 0 || next.y >= m || book[next.x][next.y] == 1 || map[next.x][next.y] == '#')//判斷是否可走和越界 
				continue;
			next.kind = now.kind;  // 記錄種類 
			book[next.x][next.y] = 1;  // 標記已走 
		//	printf("%d %d %d\n",next.x,next.y,next.step);
			if(now.kind)  // 若為人 順帶記錄步數 
				next.step = now.step + 1; 
			q.push(next); //入佇列 
		}
	}
	cout << "IMPOSSIBLE" << endl;
}
int main(){
	int z;
	cin >> z;
	while(z--){
		while(!q.empty()) q.pop();   // 清空很重要 
		memset(map,0,sizeof(map));
		memset(book,0,sizeof(book));
		ans = 0;
		cin >> n >> m;
		for(int i = 0 ; i < n ; i++)
			cin >> map[i];              // 輸入地圖資訊 
		for(int i = 0 ; i < n ; i++){
			for(int j = 0 ; j < m ; j++){
				if(map[i][j] == 'J'){    // 查詢人的起始位置 
					ren.x = i;
					ren.y = j;
					ren.step = 0;
					ren.kind = 1;
				}
				if(map[i][j] == 'F'){   // 查詢所有火的起始位置 
					fire[ans].x = i;
					fire[ans].y = j;
					fire[ans].kind = 0;
					fire[ans].step = 0;
					ans ++;
					book[i][j]=1;
				}
			}
		}
		bfs();
	}
	return 0;
}
/*
2
4 4
####
#JF#
#..#
#..#
3 3
###
#J.
#.F
*/