Fire Game(判断联通块+2元起点)

Fire Game FZU - 2150

胖哥和迷宫在 N*M 棋盘(N 行,M 列)上玩一种特殊的(无尽)游戏。一开始,这个板的每个网格都由草组成或只是空的,然后他们开始发射所有的草首先他们选择两个由草和火组成的网格。众所周知,火可以在草丛中蔓延。如果网格 (x, y) 在时间 t 触发,则与该网格相邻的网格将在时间 t+1 触发,该时间指的是网格 (x+1, y), (x-1, y), (x, y+1), (x, y-1)。当没有新网格起火时,此过程结束。如果然后所有由草组成的网格都被烧毁,胖哥和迷宫将站在网格中间,玩一个更特别(无尽)的游戏。(也许是上一题解密的OOXX游戏,谁知道呢。)

您可以假设棋盘上的草永远不会烧毁,空网格永远不会着火。

请注意,他们选择的两个网格可以相同。

输入
日期的第一行是一个整数T,它是文本案例的数量。

然后是 T 个案例,每个案例包含两个整数 N 和 M 表示棋盘的大小。然后是 N 行,每行 M 字符显示板。“#”表示草。您可以假设棋盘上至少有一个由草组成的网格。

1 <= T <=100, 1 <= n <=10, 1 <= m <=10

输出
对于每个案例,首先输出案例编号,如果他们可以玩更多特殊(无尽)游戏(点燃所有草),则输出他们在点燃后需要等待的最短时间,否则就输出-1。有关更多详细信息,请参阅示例输入和输出。

样本输入
4
3 3
.#.

.#.
3 3
.#.
#.#
.#.
3 3

#.#

3 3

…#
#.#

输出:
Case 1: 1
Case 2: -1
Case 3: 0
Case 4: 2
题意:任选择两块草地,看烧光所有草地所需要的时间,如果不能烧光则输出-1,我们先来考虑不能烧光的情况,如果草地联通块大于2,则肯定不能烧光,所以用dfs跑一下联通块就好了,其余情况用4个for枚举双起点,注意如果有2个联通块时,这个2个起点是不能属于同一个联通块的,所以我们在跑dfs要用数组below来标记一下属于哪个联通块。

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
int vist[20][20];
char e[20][20];
int below[20][20];
int cnt=0,n,m;
int dx[6]={0,0,0,1,-1};
int dy[6]={0,1,-1,0,0};
struct node{
	int x;
	int y;
	int step;
};
bool check(int x,int y)
{
	if(vist[x][y]==1||x<=0||x>n||y<=0||y>m||e[x][y]!='#') return true;
	else return false;
}
void dfs(int x,int y){
	
	vist[x][y]=1;
	below[x][y]=cnt+1;
	for(int i=1;i<=4;i++){
		int newx=x+dx[i];
		int newy=y+dy[i];
		if(check(newx,newy)) continue;
		dfs(newx,newy);
	}
}
int bfs(int x1,int y1,int x2,int y2)
{
	int cost=0;
	memset(vist,0,sizeof(vist));
	queue<node> q;
	q.push({x1,y1,0});//把2个起点同时压入队列;
	q.push({x2,y2,0});
	vist[x1][y1]=1;
	vist[x2][y2]=1;
	while(!q.empty()){
		node cur=q.front();
	    cost=max(cost,cur.step);//烧完的最长时间
		q.pop();
		for(int i=1;i<=4;i++){
			int newx=cur.x+dx[i];
			int newy=cur.y+dy[i];
			if(check(newx,newy)) continue;
			q.push({newx,newy,cur.step+1});
			vist[newx][newy]=1;
		}
	}
	return cost;
}
int main()
{
	int t,i,j,a,b,k;
	cin>>t;
	for(k=1;k<=t;k++){//读入数据
		cin>>n>>m;
		for(i=1;i<=n;i++){
			for(j=1;j<=m;j++){
				cin>>e[i][j];
			}
		}
		
		cnt=0;
		memset(below,0,sizeof(below));
		memset(vist,0,sizeof(vist));
		for(i=1;i<=n;i++){//判断联通块的数目
			for(j=1;j<=m;j++){
				if(!vist[i][j]&&e[i][j]=='#'){
					dfs(i,j);
					cnt++;
				}
			}
		}
		printf("Case %d: ",k);
		if(cnt>2){
			printf("-1\n");
		continue;
		}
		int MAX=INT_MAX;
		for(i=1;i<=n;i++){//枚举2个起点
			for(j=1;j<=m;j++){
				for(a=1;a<=n;a++){
					for(b=1;b<=m;b++){
						if(below[i][j]==1&&below[a][b]==cnt){//如果只有1个联通块时,cnt=1,2个其他属于同一个联通块,如果有2个起点时,cnt=2;这时候就要求要属于不同的联通块
							MAX=min(MAX,bfs(i,j,a,b));//每个方案的最短时间
						}
					}
				}
			}
		}
		printf("%d\n",MAX);
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值