foj 2150 Fire Games 双向广搜
题意
有一块 n*m 的地,‘ # ’ 代表草地,‘ . ’ 代表空地;两个人任意分别选取一个点开始点火(两个人选的点可重合),只有草地能着火,并且上下左右如果有草地的话可以蔓延。从一块草地烧到另一块草地的时间为 1 ,问:这块地草地完全着火的最短时间是多少?
注意
草地虽然着火,但是并不损坏——意思就是某块草地烧着以后,其他地方的火还可以从这里蔓延经过。
题目双向广搜的意思是从两个点同时开始广搜
思路
- 首先 BFS 深搜判断这块地是否有不大于两个的连通块草地,因为最多有两个着火点,可能有某块草地被孤立没有烧着。
- 其次枚举两个人的所有可能的起点,同时开始广度搜索(就像着火一样蔓延),并且在搜索时用 book [ ] [ ] 数组标记记录着火的时间点(代码中会有注释),直到搜索结束。
- 遍历二维 book [ ] [ ] 数组,找到最大的着火时间值。
- 继续以两人其他可能的起点遍历。执行步骤 2 ,知道所有可能的起点遍历完。
- 对于步骤 3 找到的所有最大着火事间值,找到最小值。
撸代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
#define N 12/**行*/
#define M 12/**列*/
char s[N][M];/** 要搜索的图*/
struct node
{
int x,y;
};
int book[N][M];/**标记数组*/
int n,m;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
void dfs(int x,int y)/*深搜,每次深搜得到一个连通块*/
{
book[x][y]=1;
for(int i=0;i<4;i++)
{
int tx=x+dir[i][0];
int ty=y+dir[i][1];
if(tx<0||ty<0||ty>=m||tx>=n||s[tx][ty]=='.'||book[tx][ty])
continue;
book[tx][ty]=1;
dfs(tx,ty);
}
return;
}
int bfs(int Sx,int Sy,int Tx,int Ty)/*S T 分别为两个人的起点*/
{
node u,v;
u.x=Sx; v.x=Tx;
u.y=Sy; v.y=Ty;
memset(book,0x3f3f3f3f,sizeof(book));
queue<node>Q;
Q.push(u);
Q.push(v);/*同时加入队列,开始广搜*/
book[Sx][Sy]=book[Tx][Ty]=0;/*事间初始值:本题从一块到另一块 时间才加1*/
while(!Q.empty())
{
u=Q.front();
Q.pop();
for(int i=0;i<4;i++)
{
int tx=u.x+dir[i][0];
int ty=u.y+dir[i][1];
if(tx<0||ty<0||tx>=n||ty>=m||s[tx][ty]=='.'||book[tx][ty]<=book[u.x][u.y]+1)/*计算草地着火时间的最小值*/
continue;
book[tx][ty]=book[u.x][u.y]+1;)/*计算草地着火时间的最小值*/
v.x=tx;
v.y=ty;
Q.push(v);
}
}
int maxx=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(s[i][j]=='#')
maxx=maxx<book[i][j]?book[i][j]:maxx;/*找到该情况最大的着火时间值*/
}
// printf("%d %d ,%d %d maxx=%d\n",Sx,Sy,Tx,Ty,maxx);
return maxx;
}
int main()
{
int t;
int Case=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%s",s[i]);
int num=0;
memset(book,0,sizeof(book));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(s[i][j]=='#'&&num<=2&&book[i][j]==0)
{
num++;
dfs(i,j);/*寻找连通块*/
}
}
}
if(num>2)
{
printf("Case %d: -1\n",Case++);
continue;
}
int ans=0x3f3f3f3f;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j]=='#')
for(int u=0;u<n;u++)
for(int v=0;v<m;v++)
{
if(s[u][v]=='#')
{
memset(book,0,sizeof(book));
int temp=bfs(i,j,u,v);
ans=ans>temp?temp:ans;/*比较得出最优时间*/
}
}
printf("Case %d: %d\n",Case++,ans);
}
return 0;
}