P1387 最大正方形
题目描述
在一个n*m的只包含0和1的矩阵里找出一个不包含0的最大正方形,输出边长。
输入格式
输入文件第一行为两个整数n,m(1<=n,m<=100),接下来n行,每行m个数字,用空格隔开,0或1.
输出格式
一个整数,最大正方形的边长
输入输出样例
输入 #1复制
4 4 0 1 1 1 1 1 1 0 0 1 1 0 1 1 0 1输出 #1复制
2
一开始无从下手,不知道得到矩阵后怎么去判断正方形。
去翻看网上其他人的做法,大致就暴力+二维前缀和或者dp。
这里总结的做法是dp,也用到了前缀处理。
就放在这里做笔记。
思路():
1.准备两个数组,一个是记录某位置左边 left_count[ ][ ](不包括此位置)连续为 1 的个数,另一个同理,求此位置的上面 up_count[ ][ ]。这样就得到了可能的最大正方形边长 min(left_count[i][j - 1], up_count[i - 1][j]);
2. dp 求出每个位置,以这个位置为正方形的右下角,能构成的最大正方形的边长。
3.如果位置a[i][j] == 1,那么最大正方形边长应为 dp[i - 1][j - 1],min(left_count[i][j - 1], up_count[i - 1][j])中的最小值。
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
int n, m;
scanf("%d %d", &n, &m);
int a[105][105] = {0};
int dp[105][105] = {0};
int left_count[105][105] = {0}; // (i, j) 位置(不包括 (i, j) )左边连续的 1 的个数
int up_count[105][105] = {0}; // (i, j) 位置(不包括 (i, j) )上面连续的 1 的个数
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
scanf("%d", &a[i][j]);
}
}
// 左边前缀处理
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (a[i][j]) left_count[i][j]+= left_count[i][j - 1] + a[i][j];
else left_count[i][j] = 0;
}
}
// 上边前缀处理
for (int j = 1; j <= m; j++)
{
for (int i = 1; i <= n; i++)
{
if (a[i][j]) up_count[i][j] = up_count[i - 1][j] + a[i][j];
else up_count[i][j] = 0;
}
}
int res = 0;
// dp 求出每个位置,以这个位置为正方形的右下角,能构成的最大正方形的边长
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (a[i][j]) dp[i][j] = min(dp[i - 1][j - 1], min(left_count[i][j - 1], up_count[i - 1][j])) + 1, res = max(res, dp[i][j]);
}
}
printf("%d\n", res);
return 0;
}