FZU-2150 Fire Game

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int INF = 1e6;
const int maxn = 10 + 5;
char board[maxn][maxn];         //记录草坪
int sign[maxn][maxn];           //访问后标记
int dx[4] = {-1, 1, 0, 0};      //x的移动
int dy[4] = {0, 0, -1, 1};      //y的移动
int t, n, m, TIME, cas, ans;
bool flag;             
struct Step
{
    int x;
    int y;
    int step;
} Maze, Fat;                    //记录选择的第一个坐标 和 选择的第二个坐标 step记录步数
queue<Step> fire;

bool judge(int x, int y)        //判断是否超出范围 是否是草 是否没烧过
{
    if(x >= 0 && y >= 0 && x < n && y < m && board[x][y] == '#' && !sign[x][y])
        return true;
    else
        return false;
}

void bfs()
{
    memset(sign, 0, sizeof(sign));      //每次重新选择 点 的时候,都要重置访问数组
    sign[Maze.x][Maze.y] = 1;           //标记第一个点
    sign[Fat.x][Fat.y] = 1;             //标记第二个点
    while(!fire.empty())                //清空队列
        fire.pop();
    fire.push(Maze);                    //放入第一个点
    fire.push(Fat);                     //放入第二个点
    while(!fire.empty())
    {
        Step Now = fire.front();
        ans = Now.step;                     //ans记录步数(即 题目中的时间)
        fire.pop();
        for(int i = 0 ; i < 4; i ++)        //上下左右四个方向烧
        {
            Step Next = Now;
            Next.x += dx[i];
            Next.y += dy[i];
            Next.step ++;                   //移动一次 步数 +1
            if(judge(Next.x, Next.y))
            {
                fire.push(Next);            //满足条件 投入队列
                sign[Next.x][Next.y] = 1;   //标记
            }
        }
    }
    return;
}

int main()
{
    scanf("%d", &t);
    cas = 0;
    while(t --)
    {
        scanf("%d %d", & n, & m);
        for(int i = 0; i < n; i ++)
            scanf("%s", board[i]);              //输入草坪
        TIME = INF;
        int cnt = 0;
        for(int i = 0; i < n; i ++)
            for(int j = 0; j < m; j ++)
                if(board[i][j] == '#')
                    cnt ++;                     //记录草的数量 只为草的数量 = 1 时做准备
        if(cnt == 1)                            //如果草的数量 = 1,则直接输出0
        {
            printf("Case %d: 0\n", ++ cas);
            continue;
        }
        for(int i1 = 0; i1 < n; i1 ++)
        {
            for(int j1 = 0; j1 < m; j1 ++)
            {
                if(board[i1][j1] == '#')        //找到第一个草的位置
                {
                    Maze.x = i1;
                    Maze.y = j1;
                    Maze.step = 0;
                    for(int i2 = i1; i2 < n; i2 ++) //向下枚举第二个草的位置
                    {
                        for(int j2 = 0; j2 < m; j2 ++)
                        {
                            if(i2 == i1 && j2 <= j1)    //避免重复
                                continue;
                            if(board[i2][j2] == '#')    //找到第二个草的位置
                            {
                                Fat.x = i2;
                                Fat.y = j2;
                                Fat.step = 0;
                                bfs();                  //bfs
                                bool flag = true;       //初始flag
                                for(int i = 0; i < n; i ++)
                                {
                                    for(int j = 0; j < m; j ++)
                                    {
                                        if(board[i][j] == '#' && !sign[i][j])   //如果平地上还有未烧掉的草 则此方案是不行的
                                        {
                                            flag = false;       //不行
                                            break;              //并跳出
                                        }
                                    }
                                    if(!flag)
                                        break;
                                }
                                if(flag)            //如果flag还是true 则说明草烧光 满足题意
                                    TIME = min(TIME, ans);      //取最小步数(最少的时间)
                            }
                        }
                    }
                }
            }
        }
        if(TIME != INF)         //当 TIME != INF 说明有解
            printf("Case %d: %d\n", ++ cas, TIME);
        else
            printf("Case %d: -1\n", ++ cas);
    }
    return 0;
}

题意:
两个熊孩子 Fat、Maze 要放火烧草(#)。火成十字形蔓延(上下左右)。空地 . 不能烧到。他们各点燃一个地方,问最少多少时间烧光草(点燃的地方时间 = 0),输出最短时间,不能烧完则输出-1。
题解:
下午两个小时。晚上三个小时。一开始的思路是对的,就是枚举(题目数据小)所有两个人可以点的地方并且用BFS标记计步数,最后取最小值。
错误1:比赛的时候我认为投入两个元素,就应该2个同时进行入队出队以达到时间同步的目的,后来才知道,其实一直只要一个Now和一个Next就行,不用Now1、Now2、Next1、Next2这样同时进行(反而错)。因为Now记录每一步的信息,时间同步体现在step和出队顺序,sign标记顺序依旧是正确的(从两点开始 不断蔓延,并不是一点蔓延完全,才蔓延另一点)。ans不需要取最大值(ans = max(ans, Next.step)),最后一步一定是这两点烧草的时间。
错误2:手贱 + 脑残 吧,打错94行(for(int j2 = j2 + 1; j2 < m; j2 ++)),
导致一直不能进入此循环…..不过即使将j2 + 1改为j1 + 1也是错误的,(居然一开始没意识到..)因为循环到下一行后每次列都是从 j1 + 1开始,导致枚举出现遗漏。
错误3:
将所有的小错误消除后,例子也是对的,满怀信心地把代码扔进去检验,结果WA了…真检查不出来,觉得已经完美了,后来发现自己进行bfs的前提是要有两个草,如果总共只有一个草是不可能进入到下面的循环并判断的,所以将草的数量为1的时候 拿出来另外处理(也就是为什么要cnt计数了),

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值