FZU 2150 Fire Game 多起点BFS

Problem 2150 Fire Game

Accept: 655    Submit: 2512
Time Limit: 1000 mSec    Memory Limit : 32768 KB

Problem Description

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.

Sample Input

4
3 3
.#.
###
.#.
3 3
.#.
#.#
.#.
3 3
...
#.#
...
3 3
###
..#
#.#

Sample Output

Case 1: 1
Case 2: -1
Case 3: 0
Case 4: 2

题意:在地图上找两个合法的起点,每个点可以影响其上下左右四个相邻点(如果存在),问最少需要几步使所有的点都受到影响。

分析:

1.首先要做的当然就是找到那两个起点,直接枚举就行。

2.找到的两个起点可能是同一个点,也可能是不同的点,需要判断一下,相同就只让一个入队列,不同就两个都入队列。

3.之后就是单纯的BFS,入队出队,就是结束条件不太一样,这里的结束条件是当所有的草坪都被影响到,所以声明一个判断函数,然后就是每一次搜索的结果可能不会一样,有的搜索甚至找不到最终结果,所以,对于最终的结果,需要仔细处理

(1)只有当从未找到结果的时候,step才能为-1

(2)找到结果后,不仅要判断是不是步数更少,还要判断step是不是-1

#include <iostream>
#include <cmath>
#include <stdio.h>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <iomanip>
#include <algorithm>
#include <memory.h>
#define MAX 20
using namespace std;
struct P//记录位置的结构体
{
    int r,c;
    int step;
};

struct Grass//记录所有草坪位置的结构体
{
    P p[MAX*MAX];
    int num;//草坪的数量
};
Grass grass;
char Map[MAX][MAX];//地图
int visit[MAX][MAX];//BFS中最重要的visit数组
int n,m;//行,列
int step;//最终所花的时间
int dirr[4]={-1,1,0,0};//方向数组
int dirc[4]={0,0,-1,1};



int judge()//判断是不是所有草坪都被烧光了
{
    int i;
    for(i=0;i<grass.num;i++)
    {
        if(visit[grass.p[i].r][grass.p[i].c]==0)
            return 0;
    }
    return 1;
}

void show()//调试时使用,输出visit数组
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cout<<visit[i][j]<<' ';
        }
        cout<<endl;
    }

}


void bfs(P p1,P p2)//广搜
{
    int i,j,R,C;
    int Max_step=0;//每一次搜索不同的起点所需的时间
    queue<P> q;
    if(p1.c==p2.c&&p1.r==p2.r)//两个起点相同
    {
        p1.step=0;
        q.push(p1);
        visit[p1.r][p1.c]=1;
    }
    else//两个起点不同
    {
        p1.step=0;
        p2.step=0;
        q.push(p1);
        q.push(p2);
        visit[p1.r][p1.c]=1;
        visit[p2.r][p2.c]=1;
    }
    while(!q.empty())
    {
        P temp=q.front();
        q.pop();
        if(judge())//判断是否全部烧完
        {
            if((Max_step<step)||(step==-1))//如果上次搜索所用的时间较多或者之前未找到结果
            {
                step=Max_step;
            }
            return;
        }
        for(i=0;i<4;i++)//四向搜索
        {
            R=temp.r+dirr[i];
            C=temp.c+dirc[i];
            if(R>=0&&R<n&&C>=0&&C<m&&Map[R][C]=='#'&&visit[R][C]==0)
            {
                P next;
                next.r=R;
                next.c=C;
                next.step=temp.step+1;
                if(Max_step<next.step)//记录本次搜索所需的最大时间
                    Max_step=next.step;
                q.push(next);
                visit[R][C]=1;
            }
        }
    }
    if(step==-1||step==999999)//如果从来都没有搜索到结果
    step=-1;
}

int main()
{
    int i,j,t,cas;
    cin>>t;
    for(cas=1;cas<=t;cas++)
    {
        step=999999;
        grass.num=0;
        cin>>n>>m;
        for(i=0;i<n;i++)//输入数据
        {
            for(j=0;j<m;j++)
            {
                cin>>Map[i][j];
                if(Map[i][j]=='#')
                {
                    grass.p[grass.num].r=i;
                    grass.p[grass.num].c=j;
                    grass.num++;
                }
            }
        }
        for(i=0;i<grass.num;i++)//枚举所有可能的起点,进行搜索
        {
            for(j=i;j<grass.num;j++)
            {
                memset(visit,0,sizeof(visit));//每次搜索都要初始化visit数组
                bfs(grass.p[i],grass.p[j]);
            }
        }
        cout<<"Case "<<cas<<": "<<step<<endl;
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值