H - Fire Game(玩火游戏)——多源点bfs搜索

Fire Game

在这里插入图片描述

题意:两小儿在平地上有草的地方点火,火向方蔓延,问平地能否烧完,若能,输出最少时间,否则输出-1.

解题思路:针对确定好了的点火位置,我们可能会有两个源点(即两小儿点火位置不同,即多源点),我们则要从这两个点开始bfs,又因为这两个是相互关联的,所以我们没必要进行两趟bfs搜索,而是将这两个点入队即可,同样设置辅助数组来判断某个状态点是否访问,同时,利用结构体来实现坐标与当前状态消耗时间的关系。由于我们是要判断是否烧完,所以我们要进行烧完的格子数统计,再与平地上有草的格子数进行比较,若烧完,则有解。这里对于点火位置我们是不知道的,即我们得枚举所有的点火方案,再逐一比对进行判断得出最小值,利用无穷大表示无解
AC代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<stack>
#include<queue>
#include<cstring>
#include<memory.h>
#include<map>
#include<iterator>
#include<list>
#include<set>
#include<functional>

using namespace std;

const int maxn=11;//最大长和宽
char graph[maxn][maxn];//表示平地
int t,n,m;//t组测试用例,n*m代表平地的大小
bool visited[maxn][maxn];//辅助数组,判断该点是否被访问过
int go[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//火的四个行动路径,记住是同时蔓延。
const int INF=0x3f3f3f3f;//表示无穷大。
int sum;//可以燃烧的点数。
typedef struct node
{
	int x,y;//当前状态火的坐标
	int time;//表示烧到当前状态所用时间
}node;
bool check(int x,int y){//检查函数,判断该点是否可行
	if(x<0||x>=n||y<0||y>=m)//出界了
		return false;
	else if(graph[x][y]!='#'){//说明该点不是草地,无法燃烧
		return false;
	}
	else if(visited[x][y]){
		//如果被访问过
		return false;
	}
	return true;
}
int bfs(int X1,int Y1,int X2,int Y2){
    queue<node> Q;
    node t1,t2;
    memset(visited,false,sizeof(visited));//初始化辅助数组。
    int num=0;//代表已被烧的火的个数。
	int maxx=0;//用于存储燃烧完所消耗时间的最大值
    t1.x=X1;t1.y=Y1;t1.time=0;//保存坐标,初始化起始点。
	t2.x=X2;t2.y=Y2;t2.time=0;
	if(t1.x==t2.x&&t1.y==t2.y){
		num=1;//说明起始源点为同一个点。
		Q.push(t1);
	}
	else{
		num=2;//说明不同,则两源点同时入队
		Q.push(t1);
		Q.push(t2);
	}
	//置标志为已访问
	visited[X1][Y1]=true;
	visited[X2][Y2]=true;
	//因为都已入队,接下来我们利用t1和t2来实现我们的bfs搜索
	while(!Q.empty()){
		t1=Q.front();//取队头元素
		Q.pop();
		for(int i=0;i<4;i++){
			t2.x=t1.x+go[i][0];
			t2.y=t1.y+go[i][1];
			if(check(t2.x,t2.y)){
				//说明符合条件
				num++;//被燃烧的点+1;
				t2.time=t1.time+1;
				if(t2.time>maxx){
					maxx=t2.time;
				}
				visited[t2.x][t2.y]=true;
				Q.push(t2);
			}
		}
	}
	if(num<sum){
		return INF;//没有烧完,返回
	}
	else
		return maxx;//这场路径的最后消耗的时间。
}
int main(){
    while(cin>>t){
		for(int i=1;i<=t;i++){
			int result=INF;
			int maxx;//接收bfs返回的结果
			sum=0;
			cin>>n>>m;
			getchar();//回收换行符
			for(int i1=0;i1<n;i1++){
				for(int j1=0;j1<m;j1++){
					scanf("%c",&graph[i1][j1]);
					if(graph[i1][j1]=='#')
						sum++;//得出应该燃烧的格子数目。
				}
				getchar();//回收换行符
			}
			//接下来开始判断所有结果,找出最小值。
			for(int i1=0;i1<n;i1++){
				for(int j1=0;j1<m;j1++){
					if(graph[i1][j1]=='#'){
						//开始寻找下一个点。
						for(int i2=i1;i2<n;i2++){
							for(int j2=0;j2<m;j2++){
								if(i1!=i2||j2>=j1){
									if(graph[i2][j2]=='#'){
										//已找到,开始bfs搜索
										maxx=bfs(i1,j1,i2,j2);
										result=min(result,maxx);
									}
								}
							}
						}
					}
				}
			}
			if(result==INF){
				cout<<"Case "<<i<<": -1"<<endl;
			}
			else{
				cout<<"Case "<<i<<": "<<result<<endl;
			}
		}
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hzf0701/article/details/107569850
今日推荐