问题描述
现有H×WH×WH×W个边长为1cm的正方形瓷砖排列在一起,其中有一部分瓷砖沾有污迹,求仅由干净瓷砖构成的最大正方形的面积。
输入:
HHH WWW
c1,1c_{1,1}c1,1 c1,2c_{1,2}c1,2 … c1,Wc_{1,W}c1,W
c2,1c_{2,1}c2,1 c2,2c_{2,2}c2,2 … c2,Wc_{2,W}c2,W
…
cH,1c_{H,1}cH,1 cH,2c_{H,2}cH,2 … cH,Wc_{H,W}cH,W
第1行输入2个整数H、W,用空格隔开。接下来H行输入H×WH×WH×W个代表瓷砖的整数cijc_{ij}cij。为1表示瓷砖有污渍,为0表示干净
输出:
输出面积的最大值,占1行
限制:
1 ≤ H,W ≤ 1400
输入示例
4 5
0 0 1 0 0
1 0 0 0 0
0 0 0 1 0
0 0 0 1 0
输出示例
4
讲解
首先,本题最容易想到的方法就是检查所有正方形内是否包含1,复杂度为O(HW×min(H,W)3)O(HW×min(H,W)^3)O(HW×min(H,W)3)。
如果用动态规划法求解,可将复杂度控制在O(HW)O(HW)O(HW)。设存储小规模局部问题的内存空间(变量)为dp[H][W],dp[i][j]中存储着从瓷砖(i,j)向左上方扩展可形成的最大正方形的边长(瓷砖数)。
dp[i][j]的值等于其左上、上方、左侧元素中最小的值加1。
从下面的伪代码中可以看出,各行的处理从左侧向右侧进行,整体如同自上而下的逐行扫描。这样一来,下面一行在计算dp[i][j]时,其左上、上方、左侧的元素值都已经计算完毕,可以直接使用
用动态规划法求最大正方形:
for i = 1 to H-1
for j = 1 to W-1
如果G[i][j]沾有污渍
dp[i][j] = 0
else
dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1])) + 1
maxWidth = max(maxWidth, dp[i][j])
AC代码如下
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 1400
int dp[MAX][MAX], G[MAX][MAX];
int getLargestSquare(int H, int W) {
int maxWidth = 0;
for(int i = 0; i < H; i++) {
for(int j = 0; j < W; j++) {
dp[i][j] = (G[i][j] + 1) % 2;
maxWidth |= dp[i][j];
}
}
for(int i = 1; i < H; i++) {
for(int j = 1; j < W; j++) {
if(G[i][j]) {
dp[i][j] = 0;
} else {
dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]) ) + 1;
maxWidth = max(maxWidth, dp[i][j]);
}
}
}
return maxWidth * maxWidth;
}
int main(){
int H, W;
scanf("%d %d", &H, &W);
for(int i = 0; i < H; i++) {
for(int j = 0; j < W; j++) scanf("%d", &G[i][j]);
}
printf("%d\n", getLargestSquare(H, W));
return 0;
}