题目链接:2018 ICPC Asia Nakhon Pathom Regional Contest (PDF)
题意:n * m 的只含有 0 1 的矩阵,找一个正方形使得正方形中的 1 的数量不能超过 1 ,问正方形最大边长。
思路:
- 答案是线性的,首先想到二分答案
- 但是判断当前长度是否满足条件的时候我们不能进行暴力,然后就是想到前缀和,求前缀和的方法很容易理解。
sum [ i ][ j ] = sum[ i ][ j - 1 ] + sum[ i - 1 ][ j ] - sum[ i - 1 ][ j - 1 ] + a[ i ]
表示 i,j 位置的前缀和
卡常
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 1010;
int n, m;
int sum[N][N];
int a[N][N];
bool judge(int x)//判断当前长度是否合法
{
int len = m - x;
int wid = n - x;
// cout << x << "--" << len << "--" << wid << endl;
for(int i = 1; i <= wid; i++)
{
for(int j = 1; j <= len; j++)
{
int now = sum[i + x][j + x] - sum[i - 1][j + x] - sum[i + x][j - 1] + sum[i - 1][j - 1];
// cout << now << endl;
// cout << i << " " << j << endl;
if(now <= 1) return true;
}
}
return false;
}
template <class T>//输入挂
inline void scan_d(T &ret)
{
char c;
ret = 0;
while((c = getchar()) < '0' || c > '9');
while(c >= '0' && c <= '9')
{
ret = ret * 10 + (c - '0'), c = getchar();
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scan_d(n);
scan_d(m);
int mx = max(m, n);
for(int i = 0; i <= mx; i++)
{
for(int j = 0; j <= mx; j++)
{
sum[i][j] = 0;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
scan_d(a[i][j]);
sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + a[i][j];
}
}
// cout << "-----" << endl;
// for(int i = 1; i <= n; i++)
// {
// for(int j = 1; j <= m; j++)
// {
// cout << sum[i][j] << " ";
// }
// cout << endl;
// }
// cout << "-----" << endl;
int ans = 1;
int l = 1, r = min(n, m);
while(l <= r)
{
int mid = (l + r) / 2;
if(judge(mid))
{
ans = max(ans, mid);
// cout << l << " " << r << " " << mid << endl;
l = mid + 1;
}
else
{
r = mid - 1;
}
}
printf("%d\n", ans + 1);
}
return 0;
}