fzu 2150 Fire Game(双起点BFS)

传送门
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。
题解: 找最短的时间,图也不大,就枚举咯,去找出到底烧哪两个草地花费最少的时间。问题在,怎么求两个草地同时烧起来的时间?双起点bfs,一开始想都不敢想这个东西,但是再做的时候,又特别自然地就觉得就应该这么做,没看关于双起点的一些博客,自己就尝试出来了。

int bfs(int x, int y, int a, int b){//双起点
    int t = 0;
    node front, next;
    front.x = x, front.y = y, front.t = 0;
    next.x = a, next.y = b, next.t = 0;
    vis[x][y] = vis[a][b] = 1;
    queue<node> q;
    q.push(front);
    q.push(next);
    //双起点听着有点玄乎,其实就是同时将他们扔进队列而已

    while(!q.empty()){
        ......
    }
    return t;
}

我的思路也很明确,小错误也少了很多,还算比较快地写出来了,但是以提交,wa地一下就哭出来了,WA了,不讲道理地wa了(不是,主要还是我菜)。在同学的帮助下,找到了错误,整体代码是没有问题,只是忽略了一些特殊的样例,比如土地中从来就没有草地,或者只有一个,这是原来的代码中忽视的,我默认他至少有两个以上的草地,所以这两个特殊样例在我的原代码中会输出-1。调整:

if(tt<=2)	ans = 0;//两个草地以内的,放火甚至不放火就能烧完的,不花费时间的

就是一个双起点吧,没有写过可能有些懵逼,但其实想一想,就是把两个起点在while(!q.empty())之前同时扔进队列而已,其他的步骤几乎是一样的。其实就是我的问题,忽视了一些特殊样例,以后做到这样的题目可以找一些极端样例去运行(诸如全是草,没有草之类的)。

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

int T, n, m;
int vis[12][12];
char mp[12][12];
int dir[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
struct node{    int x, y, t;};

void init(){
    for (int i = 0; i < 12; i++)
        for (int j = 0; j < 12; j++)
            vis[i][j] = 0;
}

int check(node &a){
    if(a.x<0 || a.x>=n || a.y<0 || a.y>=m)
        return 0;
    if(mp[a.x][a.y]!='#' || vis[a.x][a.y])
        return 0;
    return 1;
}

int bfs(int x, int y, int a, int b){//双起点
    int t = 0;
    node front, next;
    front.x = x, front.y = y, front.t = 0;
    next.x = a, next.y = b, next.t = 0;
    vis[x][y] = vis[a][b] = 1;
    queue<node> q;
    q.push(front);
    q.push(next);
    //双起点听着有点玄乎,其实就是同时将他们扔进队列而已

    while(!q.empty()){
        front = q.front();
        q.pop();

        for (int i = 0; i < 4; i++){
            next.x = front.x + dir[i][0];
            next.y = front.y + dir[i][1];
            next.t = front.t + 1;
            if(check(next)){
            	vis[next.x][next.y] = 1;
                if(next.t > t)    t = next.t;
                q.push(next);
            }
        }
    }
    for(int i=0; i<n; i++){
    	for(int j=0; j<m; j++)
    		if(mp[i][j]=='#' && !vis[i][j]){//是草地、并且未访问 = 没烧着
    			t = -1;//火烧了以后,仍然有草地没有烧到
			}
	}
    	
    			
    return t;
}
int main(){
    scanf("%d", &T);
    for (int cnt = 1; cnt <= T; cnt++){
        int ans = -1;//初始化为-1,如果怎么样都烧不完的话就输出-1
        scanf("%d%d", &n, &m);
        getchar();
        for (int i = 0; i < n; i++)
            scanf("%s", mp[i]);
		
		int tt = 0;
		node tem[110];
		for(int i=0; i<n; i++)
			for(int j=0; j<m; j++)
				if(mp[i][j]=='#'){//将所有草地的位置列入一个结构数组中
					tem[tt].x = i;
					tem[tt++].y = j;
				}
		
       	for(int i=0; i<tt; i++){
       		for(int j=i+1; j<tt; j++){
       			init();	//每次都要访问标记重置
       			int t = bfs(tem[i].x, tem[i].y, tem[j].x, tem[j].y);
       			if(t!=-1 && (ans==-1 || ans>t))	ans = t;
			}
		}
/*!!!!*/if(tt<=2)	ans = 0;//两个草地以内的,放火甚至不放火就能烧完的,不花费时间的
        printf("Case %d: %d\n", cnt, ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值