胖哥和迷宫在 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);
}
}