洛谷P1387 最大正方形

链接: https://www.luogu.org/problemnew/show/P1387

题目描述

在一个n*m的只包含0和1的矩阵里找出一个不包含0的最大正方形,输出边长。

输入格式

输入文件第一行为两个整数n,m(1<=n,m<=100),接下来n行,每行m个数字,用空格隔开,0或1.

输出格式

一个整数,最大正方形的边长

input:
4 4
0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1
output
2

解法:dp或者二分
令$dp[i][j]$表示$(i, j)$作为右下角最后一个的最长的正方形长度
显然它可以由左上方转移而来,但也可能从新增一圈,所以还需要看左边和上方。
三者取最小再加1即可。
状态转移方程

$dp[i][j] = min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]) + 1$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e3 + 10;
int a[maxn][maxn];
int dp[maxn][maxn];//dp[i][j]表示(i, j)作为右下角最后一个的最长的正方形长度
int main()
{

ios::sync_with_stdio(false);
cin.tie(0);
//freopen("/Users/vector/Desktop/in", "r", stdin);
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> a[i][j];
int ans = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(a[i][j] == 0) continue;
dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j - 1]), dp[i - 1][j]) + 1;
ans = max(ans, dp[i][j]);
}
}
cout << ans << endl;
return 0;

}