《UVA11624 Fire!》两次BFS+优化思路

这题真的好多细节问题,我调了好久,感觉自己还是好菜!
言归正传:这题我开始的思路是找到各个火的点,然后一次次bfs去调整各个点的最短蔓延到的时间,但是超时了,后来仔细一想确实,如果点有很多,那就需要很多时间去搜索了。看了大神们的博客后,才明白,其实一次去搜索蔓延时间就可以了。因为这点最短的蔓延时间会由离他最近的火的时间来覆盖,所以就只需要一次。然后我们只要去比较逃到这点的时间火有没有蔓延到就可以了。

#include<bits/stdc++.h>
using namespace std;
#define INF INT_MAX
#define INM INT_MIN
typedef long long LL;
const int N = 1005;
int n,m,vis[N][N],fire[N][N],b[4][2] = {1,0,-1,0,0,1,0,-1},sum,ans;//fire数组存储火势蔓延到这里所需要的时间.
string mp[N];
struct Node
{
    int x,y,step;
};
queue<Node> Q1;//优化思路的核心,在输入的时候就把火放入队列
void Cqueue(queue<Node> &Q)//清空队列
{
    while(!Q.empty())
    {
        Q.pop();
    }
}
void bfs1()//搜索火势,只需一次
{
    Node p,q;
    while(!Q1.empty())
    {
        q = Q1.front();
        Q1.pop();
        for(int i=0;i<4;++i)
        {
            int px = q.x+b[i][0];
            int py = q.y+b[i][1];
            if(px >= 0 && px < n && py >= 0 && py < m && vis[px][py] != 1 && mp[px][py] != '#')//不是墙就记下他的最短被蔓延到的时间
            {
                vis[px][py] = 1;
                fire[px][py] = min(fire[px][py],q.step+1);//覆盖最短的蔓延时间
                p.x = px;
                p.y = py;
                p.step = q.step+1;
                Q1.push(p);
            }
        }
    }
    return ;
}
int check(int x,int y)//判断是不是在边缘
{
    if(x == 0 || x == n-1 || y == 0 || y == m-1) return 1;
    return 0;
}
int bfs2(int x,int y)//对能否逃出的搜索
{
    memset(vis,0,sizeof(vis));
    Node p,q;
    queue<Node> Q;
    vis[x][y] = 1;
    p.x = x;p.y = y;p.step = 0;
    Q.push(p);
    while(!Q.empty())
    {
        q = Q.front();
        Q.pop();
        if(check(q.x,q.y) == 1 && q.step < fire[q.x][q.y])//判断这时候火有没有蔓延到
        {
            ans = q.step+1;
            return 1;
        }
        for(int i=0;i<4;++i)
        {
            int px = q.x+b[i][0];
            int py = q.y+b[i][1];
            if(px >= 0 && px < n && py >= 0 && py < m && vis[px][py] != 1 && mp[px][py] == '.')
            {
                if(q.step+1 < fire[px][py])//火势没有被蔓延到
                {
                    vis[px][py] = 1;
                    p.x = px;p.y = py;p.step = q.step+1;
                    Q.push(p);
                }
            }
        }
    }
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    int t,si,sj;
    Node p;
        cin >> n >> m;
        int x = 0;
        Cqueue(Q1);
        for(int i=0;i<n;++i)
            for(int j=0;j<m;++j) fire[i][j] = INF;//开始全部都蔓延不到,记为正无穷
        memset(vis,0,sizeof(vis));//这里不要忘记重置,这个细节调了好久..
        for(int i=0;i<n;++i)
        {
            cin >> mp[i];
            for(int j=0;j<m;++j)
            {
                if(mp[i][j] == 'J'){si = i;sj = j;}
                if(mp[i][j] == 'F')
                {
                    vis[i][j] = 1;//这里就是一次bfs就能搜到所有点的蔓延时间的开始处理
                    fire[i][j] = 0;//是火就一开始就被蔓延了
                    p.x = i;p.y = j;p.step = 0;
                    Q1.push(p);
                }
            }
        }
        bfs1();
        if(bfs2(si,sj) == 0) printf("IMPOSSIBLE\n");
        else
        {
            printf("%d\n",ans);
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值