foj 2150 Fire Games 双向广搜

foj 2150 Fire Games 双向广搜

题意

有一块 n*m 的地,‘ # ’ 代表草地,‘ . ’ 代表空地;两个人任意分别选取一个点开始点火(两个人选的点可重合),只有草地能着火,并且上下左右如果有草地的话可以蔓延。从一块草地烧到另一块草地的时间为 1 ,问:这块地草地完全着火的最短时间是多少?

注意

草地虽然着火,但是并不损坏——意思就是某块草地烧着以后,其他地方的火还可以从这里蔓延经过。

题目双向广搜的意思是从两个点同时开始广搜

思路

  1. 首先 BFS 深搜判断这块地是否有不大于两个的连通块草地,因为最多有两个着火点,可能有某块草地被孤立没有烧着。
  2. 其次枚举两个人的所有可能的起点,同时开始广度搜索(就像着火一样蔓延),并且在搜索时用 book [ ] [ ] 数组标记记录着火的时间点(代码中会有注释),直到搜索结束。
  3. 遍历二维 book [ ] [ ] 数组,找到最大的着火时间值。
  4. 继续以两人其他可能的起点遍历。执行步骤 2 ,知道所有可能的起点遍历完。
  5. 对于步骤 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;
}

猜你喜欢

转载自blog.csdn.net/DREAM_yao/article/details/107990634
今日推荐