【简单搜索】FZU 2150 Fire Game详解

Fire Game

Fat brother and Maze are playing a kind of special (hentai) game on an N*M board (N rows, M columns). At the beginning, each grid of this board is consisting of grass or just empty and then they start to fire all the grass. Firstly they choose two grids which are consisting of grass and set fire. As we all know, the fire can spread among the grass. If the grid (x, y) is firing at time t, the grid which is adjacent to this grid will fire at time t+1 which refers to the grid (x+1, y), (x-1, y), (x, y+1), (x, y-1). This process ends when no new grid get fire. If then all the grid which are consisting of grass is get fired, Fat brother and Maze will stand in the middle of the grid and playing a MORE special (hentai) game. (Maybe it’s the OOXX game which decrypted in the last problem, who knows.)

You can assume that the grass in the board would never burn out and the empty grid would never get fire.

Note that the two grids they choose can be the same.

Input

The first line of the date is an integer T, which is the number of the text cases.

Then T cases follow, each case contains two integers N and M indicate the size of the board. Then goes N line, each line with M character shows the board. “#” Indicates the grass. You can assume that there is at least one grid which is consisting of grass in the board.

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

Output

For each case, output the case number first, if they can play the MORE special (hentai) game (fire all the grass), output the minimal time they need to wait after they set fire, otherwise just output -1. See the sample input and output for more details.

题面翻译:

草地上有n*m个方格,有些方格有草堆,两个人准备烧掉所有的草,一个草堆着火后会在一分钟内向四周蔓延。现在两个人各自选择一个方格(可以是同一个)点燃草堆,输出烧光所有草所需的最短时间,烧不完就输出-1。

分析:

我的做法是先找图中连通块的个数,如果连通块的个数大于2显然无解。连通块的个数小于等于2时四重循环枚举两个起点进行广搜。 

代码详解:

belong数组记录每个点属于哪个连通块,0表示该点是空地,没有草。

typedef struct{
   int x,y;
   int step;
}pos;

int direct[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
const int inf=0xfffffff;

char board[15][15];
int vis[15][15];
int  belong[15][15];
int N,M;
int block_num=0;    //统计连通块个数

  连通块个数的判断也是用广搜:

  belong数组初始化为0

  先在main函数里枚举所有的点,若该点为0(表示没有草或者还没进行处理)则送进Block_search函数处理

 for(int i=1;i<=N;i++)
           for(int j=1;j<=M;j++){
              if(!belong[i][j]&&board[i][j]=='#')
                 Block_search(i,j);
        }

  以送进来的点为起点,向四周广搜,所有搜到的点都在belong数组中标记为x,x表示是第几个搜到的连通块。

void Block_search(int a,int b){   //这个搜索里其实step没用
    pos start;
    start.x=a;
    start.y=b;
    block_num++;
    queue<pos>q;
    q.push(start);
    while(!q.empty()){
        pos temp=q.front();
        belong[temp.x][temp.y]=block_num;
        q.pop();
        for(int i=0;i<4;i++){
            pos newtemp;
            newtemp.x=temp.x+direct[i][0];
            newtemp.y=temp.y+direct[i][1];
            newtemp.step=temp.step+1;
            if(newtemp.x<=N&&newtemp.x>=1&&newtemp.y<=M&&newtemp.y>=1&&!belong[newtemp.x][newtemp.y]&&board[newtemp.x][newtemp.y]=='#'){
                belong[newtemp.x][newtemp.y]=block_num;
                q.push(newtemp);
            }
        }
    }

}

   如果连通块个数大于2显然是无解的

if(block_num>2)  ans=-1;
   

   最后就是四重循环枚举两个起点,进行双起点的广搜

else{
   pos s1,s2;
   for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
                  if(belong[i][j]==1){
                        s1.step=0,s1.x=i,s1.y=j;

                         for(int a=1;a<=N;a++)
                              for(int b=1;b<=M;b++)
                                  if(belong[a][b]==block_num){
                                        s2.step=0,s2.x=a,s2.y=b;
                                        ans=min(ans,double_bfs(s1,s2));
                                  }

                     }
}

   双起点的广搜其实和普通广搜没区别,就是一开始压入了两个点而已

int double_bfs(pos start1,pos start2){
     memset(vis,0,sizeof(vis));
     int cost=0;
     queue<pos>q;

     q.push(start1);
     q.push(start2);
     vis[start1.x][start1.y]=1;
     vis[start2.x][start2.y]=1;

     while(!q.empty()){
        pos temp=q.front();
        q.pop();
        cost=max(cost,temp.step);
        for(int i=0;i<4;i++){
            pos newtemp;
            newtemp.x=temp.x+direct[i][0];
            newtemp.y=temp.y+direct[i][1];
            newtemp.step=temp.step+1;
            if(newtemp.x<=N&&newtemp.x>=1&&newtemp.y<=M&&newtemp.y>=1&&!vis[newtemp.x][newtemp.y]&&board[newtemp.x][newtemp.y]=='#'){
                vis[newtemp.x][newtemp.y]=1;
                q.push(newtemp);
            }
        }
    }
    return cost;

}

   AC代码:

#include<string.h>
#include<queue>
#include<iostream>
#include<cstdio>
using namespace std;

typedef struct{
   int x,y;
   int step;
}pos;

int direct[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
const int inf=0xfffffff;

char board[15][15];
int vis[15][15];
int  belong[15][15];
int N,M;
int block_num=0;    //统计连通块个数

void Block_search(int a,int b){   //这个搜索里其实step没用
    pos start;
    start.x=a;
    start.y=b;
    block_num++;
    queue<pos>q;
    q.push(start);
    while(!q.empty()){
        pos temp=q.front();
        belong[temp.x][temp.y]=block_num;
        q.pop();
        for(int i=0;i<4;i++){
            pos newtemp;
            newtemp.x=temp.x+direct[i][0];
            newtemp.y=temp.y+direct[i][1];
            newtemp.step=temp.step+1;
            if(newtemp.x<=N&&newtemp.x>=1&&newtemp.y<=M&&newtemp.y>=1&&!belong[newtemp.x][newtemp.y]&&board[newtemp.x][newtemp.y]=='#'){
                belong[newtemp.x][newtemp.y]=block_num;
                q.push(newtemp);
            }
        }
    }

}


int double_bfs(pos start1,pos start2){
     memset(vis,0,sizeof(vis));
     int cost=0;
     queue<pos>q;

     q.push(start1);
     q.push(start2);
     vis[start1.x][start1.y]=1;
     vis[start2.x][start2.y]=1;

     while(!q.empty()){
        pos temp=q.front();
        q.pop();
        cost=max(cost,temp.step);
        for(int i=0;i<4;i++){
            pos newtemp;
            newtemp.x=temp.x+direct[i][0];
            newtemp.y=temp.y+direct[i][1];
            newtemp.step=temp.step+1;
            if(newtemp.x<=N&&newtemp.x>=1&&newtemp.y<=M&&newtemp.y>=1&&!vis[newtemp.x][newtemp.y]&&board[newtemp.x][newtemp.y]=='#'){
                vis[newtemp.x][newtemp.y]=1;
                q.push(newtemp);
            }
        }
    }
    return cost;

}

int main()
{
    int T;
    scanf("%d",&T);
    for(int Case=1;Case<=T;Case++){
        block_num=0;
        memset(belong,0,sizeof(belong));
        int ans=inf;

        scanf("%d %d",&N,&M);
        for(int i=1;i<=N;i++)
           for(int j=1;j<=M;j++)
              scanf(" %c",&board[i][j]);

        for(int i=1;i<=N;i++)
           for(int j=1;j<=M;j++){
              if(!belong[i][j]&&board[i][j]=='#')
                 Block_search(i,j);
        }

        if(block_num>2)  ans=-1;
        else{

            pos s1,s2;
            for(int i=1;i<=N;i++)
                for(int j=1;j<=M;j++)
                    if(belong[i][j]==1){
                         s1.step=0,s1.x=i,s1.y=j;

                         for(int a=1;a<=N;a++)
                              for(int b=1;b<=M;b++)
                                  if(belong[a][b]==block_num){
                                        s2.step=0,s2.x=a,s2.y=b;
                                        ans=min(ans,double_bfs(s1,s2));
                                  }
                     }
        }
        printf("Case %d: %d\n",Case,ans);

    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值