动态规划 | 最大正方形 | Largest Square | C/C++实现

本文探讨了如何在沾有污迹的瓷砖阵列中找到最大的完全由干净瓷砖构成的正方形,并给出了动态规划法的解决方案,将复杂度降低至O(HW)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

现有 H × W H×W H×W个边长为1cm的正方形瓷砖排列在一起,其中有一部分瓷砖沾有污迹,求仅由干净瓷砖构成的最大正方形的面积。

输入:
H H H W W W
c 1 , 1 c_{1,1} c1,1 c 1 , 2 c_{1,2} c1,2 c 1 , W c_{1,W} c1,W
c 2 , 1 c_{2,1} c2,1 c 2 , 2 c_{2,2} c2,2 c 2 , W c_{2,W} c2,W

c H , 1 c_{H,1} cH,1 c H , 2 c_{H,2} cH,2 c H , W c_{H,W} cH,W
第1行输入2个整数H、W,用空格隔开。接下来H行输入 H × W H×W H×W个代表瓷砖的整数 c i j c_{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 ( H W × m i n ( H , W ) 3 ) O(HW×min(H,W)^3) O(HW×min(H,W)3)

如果用动态规划法求解,可将复杂度控制在 O ( H W ) 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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值