题目:P1387 最大正方形 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
本题可以枚举二维矩阵的每个点作为正方形的左上角顶点,然后枚举正方形的所有可能边长,然后检查该正方形内是否存在0。
如果检查的过程我们用暴力枚举的方法,检查过程复杂度将会是
其中k是我们枚举的正方形边长
那么这样的纯暴力法时间复杂度就是
题目中n最大为100,故上述方法必然会超时;
此时,我们需要对检查过程进行优化,如何快速查询一个静态二维数组的区间0的个数呢?我们将0的位置看作1,其他的数字看成0,这样区间0的个数也就转化为二维区间和的问题了!
所以我们提前利用二维前缀和维护0的个数即可,最后检查部分也就是O(1)的时间复杂度了!
所以最后本题复杂度也就被我们优化为了
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define x first
#define y second
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ull;
typedef long long ll;
const int N = 100 + 10, inf = 0x3f3f3f3f;
int pre[N][N], a[N][N];
int n, m;
void solve()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
cin >> a[i][j];
pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + (a[i][j] == 0);
}
}
int res = 0;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
if(a[i][j] == 0) continue ;
int d = min(n - i + 1, m - j + 1);
// 从大到小枚举边长可以减少计算量
for(int k = d; k >= 1; k --){
int cnt = pre[i + k - 1][j + k - 1] - pre[i - 1][j + k - 1] - pre[i + k - 1][j - 1] + pre[i - 1][j - 1];
if(cnt == 0){
res = max(res, k);
break;
}
}
}
}
cout << res << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
//cin>>t;
while( t -- )
{
solve();
}
return 0;
}