[DP] 盖房子 题解
题目描述
永恒の灵魂最近得到了面积为n*m的一大块土地(高兴ING_),他想在这块土地上建造一所房子,这个房子必须是正方形的。
但是,这块土地并非十全十美,上面有很多不平坦的地方(也可以叫瑕疵)。这些瑕疵十分恶心,以至于根本不能在上面盖一砖一瓦。
他希望找到一块最大的正方形无瑕疵土地来盖房子。
不过,这并不是什么难题,永恒の灵魂在10分钟内就轻松解决了这个问题。
现在,您也来试试吧。
输入格式
输入文件第一行为两个整数n,m(1<=n,m<=1000),接下来n行,每行m个数字,用空格隔开。0表示该块土地有瑕疵,1表示该块土地完好。
输出格式
一个整数,最大正方形的边长。
样例
样例输入
4 4
0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1
样例输出
2
题解
刚刚拿到这一题时,貌似不大会欸,但不难发现,这道题应该用DP来做,因为可以把n*m的大矩阵分成一个个的小矩阵,然后对一个个的子问题进行求解,这就体现了坐标DP的思想;
思考问题的本质,发现最小的完好土地是2 * 2的,因此我们可以从这最小的出发,每发现一个,就给2 * 2的矩阵的某一角+1(我用的是右下角)最后累积求最大,就是我们想要的答案;
其实上面的思路,总结一下就是若一个正方形的右下角坐标为(i,j),那么这个正方形的最大边长=min(i - 1, j; i - 1, j - 1; i, j - 1)+ 自己能组成的最大边长(我将信息都存在右下角,存在其他角也可以)至于为什么要取min,可参见短板效应。
代码
#include <iostream>
using namespace std;
int n, m;
int a[1005][1005];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i][j]) { //能成为合法正方形的前提是自己是合法的
a[i][j] += min(min(a[i - 1][j], a[i - 1][j - 1]), a[i][j - 1]);
ans = max(ans, a[i][j]); //所有数中找最大
}
}
}
cout << ans;
return 0;
}
后记:同机房大佬也写了这道题的题解。