[线性DP] 洛谷P1387 最大正方形(思维定势问题)
程序员文章站
2023-12-26 12:41:39
...
题目
思路
本题的DP部分和代码实现都很简单,充分迎合了普及/提高-的难度。
但大家都是怎么想出怎么用DP的。。怎么想出状态是正方形的右小角的。。我怎么想不出来。。是OI的题无论什么难度思维难度都这么高吗。。还是我比较笨。。
1.状态定义:d(i,j),(i,j)作为一个正方形的右小角,所形成的正方形的最大边长。
2.状态转移方程:
为什么状态会这样转移,需要画图
大概就是这样。
我做不出来的原因是因为思考的方向不对,因为之前做的球场那道题(实际上本题也确实可以用技巧枚举做出来),就一直在想直接枚举正方形起始点不好,一直在想怎么枚举正方形的边。这只能说明,思维定势有好有坏,但在我做题量还非常少的情况下请谨慎的使用思维定势,别一看到某道题就说是另外一道题的翻版,这样往往连正确的做法都掌握不到。
另外一个原因是,缺少足够的画图与推演。图上这个道理很明显,我就不相信自己要是半小时一直勾勾画画能想不出来,但是自己一直凭空想而不去动手。只能说,对于OI这种思维难度较高的活动,应尽自己所能更好的去想一个问题(比如画图),毕竟这不如数学或者物理那么简单,不是盯着题看凭空一想就能想出来的,需要实打实的推演。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 100 + 10;
int n, m, G[maxn][maxn], d[maxn][maxn];
int main() {
scanf("%d%d", &n, &m);
_rep(i, 1, n) _rep(j, 1, m) scanf("%d", &G[i][j]);
int ans = 0;
_rep(i, 1, n)
_rep(j, 1, m)
if (G[i][j] == 1) {
d[i][j] = min(d[i - 1][j], min(d[i][j - 1], d[i - 1][j - 1])) + 1;
ans = max(ans, d[i][j]);
}
printf("%d\n", ans);
return 0;
}