题目链接: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;
}