FZU 2150 Fire Game BFS求解

本文分享了一道ACM竞赛中关于寻找草地全部燃烧所需最短时间的问题,并通过改进暴力枚举策略,成功将时间复杂度优化,最终实现AC。文章详细介绍了作者的解题思路与过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2150

题意:给定一个草坪,两人分别点燃一个草堆(可以相同),求所有草堆都着火时的最小时间。

谈起这题也是有点悲催,TLE了好多次,看了其他人的题解再写,WA了好多次,今晚看到一篇不错的博客让我灵感来了,然后顺利AC。

这篇博客是:http://m.blog.youkuaiyun.com/blog/zzzz40/38122385,我也只是大概看了下就来灵感了,哈哈。。


所谓的灵感:大概看了下博客,发现他也是暴力枚举两个点,为什么他的就没有TLE呢?仔细一看,人家暴力的比我漂亮一点,漂亮之处在于把:

for(int i=0;i<(n*m);i++) for(int j=0;j<(n*m);j++)改为:for(int i=0;i<(n*m;i++) for(int j=i;j<(n*m);j++)。

这样一来,计算量变为了原来的1/2,你也许还会说时间复杂度不还是O((n*m)^2)吗?但实际上这样之后其实已经不会TLE了。问题是为什么这样改能够不TLE呢?看到一篇博客说,此题纯暴力的话时间复杂度会达到10^8,我也是半信半疑,毕竟对时间复杂度的计算不是很清楚。我对此题的时间复杂度的计算是:显然两个for循环的时间复杂度为O((m*n)^2)=10^4。然后计算BFS的时间复杂度:显然每层有一个for循环,循环量为4,最大层为对角线,为10层,这样总的复杂度为4^10,在乘上前面的复杂度,显然超时!但事实并不是这样,我们可以这样想,由矩形的形状可以推知,其实左上角和右下角的计算量应该是一个数量级的,为什么这样说呢?因为两者是对称的嘛,经过筛选后,留下的计算量应该是相等的。所以实际上的层数应该为5层。但是第一层已经作为了初始化入队了,循环量为0,只有4层了,这样一来总的时间复杂度为:10^4*(4^4)。约为:2.5*10^6。所以,在时间变为原来的1/2后(500ms+),才会AC,当然,我对计算机1s的运算量不是很清楚,从此题也可以估计出,大概也就10^6或是10^7的数量级,10^8应该会TLE。其实一开始我也觉得不应该TLE啊,可惜了我暴力的不够漂亮。。。。

还有一点,既然都这么暴力了,那么算不算连通块的数量也就变得没有意义了。

代码:

#include<iostream>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>
#define LL __int64
#define INF 0x7fffffff

using namespace std;
struct node{
    int x,y,step;
};

char Map[11][11];
int vis[11][11];
int n,m;

int d[][2]={1,0,-1,0,0,1,0,-1};

int bfs(int x,int y,int xx,int yy){
    memset(vis,0,sizeof(vis));
    vis[x][y]=vis[xx][yy]=1;
    queue<node> Q;
    Q.push((node){x,y,0});
    Q.push((node){xx,yy,0});
    int ans=-1;
    while(!Q.empty()){
        node tp=Q.front();
        ans=max(ans,tp.step);
        Q.pop();
        for(int p=0;p<4;p++){
            int tx=tp.x+d[p][0],ty=tp.y+d[p][1];
            if(tx<0|| ty<0 || tx>=n || ty>=m) continue;
            if(Map[tx][ty]=='.' || vis[tx][ty]) continue;
            Q.push((node){tx,ty,tp.step+1});
            vis[tx][ty]=1;
        }
    }
    for(int i=0;i<n;i++) for(int j=0;j<m;j++)
        if(Map[i][j]=='#' && vis[i][j]==0) return INF;
    return ans;
}


int main(){
    //freopen("D:\\in.txt","r",stdin);
    int T;cin>>T;
    for(int kase=1;kase<=T;kase++){
        cin>>n>>m;
        for(int i=0;i<n;i++) for(int j=0;j<m;j++)
            cin>>Map[i][j];
        int ans=INF;
        for(int i=0;i<n*m;i++)
            for(int j=i;j<n*m;j++)
                if(Map[i/m][i%m]=='#' && Map[j/m][j%m]=='#')
                    ans=min(bfs(i/m,i%m,j/m,j%m),ans);
        printf("Case %d: %d\n",kase,ans==INF? -1:ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值