巨大的牛棚 - 题目 - Daimayuan Online Judge
题意:
农夫约翰想要在他的正方形农场上建造一座正方形大牛棚。他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方。我们假定,他的农场划分成 n * n
的方格。输入数据中包括有树的方格的列表。你的任务是计算并输出,在他的农场中,不需要砍树却能够修建的最大正方形牛棚。牛棚的边必须和水平轴或者垂直轴平行。 考虑下面的方格,它表示农夫约翰的农场,‘.'表示没有树的方格,‘#'表示有树的方格
思路:
一开始的思路是枚举两个点,然后二维前缀和判中间是否有树,注意到数据范围O(n^4)超时
因此就想枚举一个点和枚举边长,降到O(n^3),但是1e9还是超时
枚举超时,我们就考虑二分
我们考虑二分边长
注意到,边长过大就会包含树,边长过小就不会包含树
因此边长具有单调性,因此二分是合理的
接下来就是写check函数,那就是用二维前缀和判正方形中间是否有树了
Code:
#include <bits/stdc++.h>
using namespace std;
const int mxn=1e3+10;
int n,T,x,y,ans;
int a[mxn][mxn],f[mxn][mxn];
bool check(int x){
for(int i=1;i<=n-x+1;i++){
for(int j=1;j<=n-x+1;j++){
int x1=j,y1=i,x2=j+x-1,y2=i+x-1;
if(f[x2][y2]-f[x1-1][y2]-f[x2][y1-1]+f[x1-1][y1-1]==0) return true;
}
}
return false;
}
int main(){
scanf("%d%d",&n,&T);
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
while(T--){
scanf("%d%d",&x,&y);
a[x][y]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=a[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1];
}
}
int l=1,r=1e9;
while(l<=r){
int mid=l+r>>1;
if(check(mid)){
ans=mid;
l=mid+1;
}else r=mid-1;
}
printf("%d\n",ans);
}
总结:
算法:
1.判断二维平面上矩形中间是否为空,用二维前缀和即可
2.什么时候考虑二分:
最大值最小或最小值最大的时候
我们不知道这个值是多少的时候
枚举超时的时候
求最值的时候