[线性DP] 洛谷P1387 最大正方形(思维定势问题)

题目

LP1387

思路

本题的DP部分和代码实现都很简单,充分迎合了普及/提高-的难度。
但大家都是怎么想出怎么用DP的。。怎么想出状态是正方形的右小角的。。我怎么想不出来。。是OI的题无论什么难度思维难度都这么高吗。。还是我比较笨。。


1.状态定义:d(i,j),(i,j)作为一个正方形的右小角,所形成的正方形的最大边长。
2.状态转移方程:

d ( i , j ) = m i n { d ( i 1 , j ) , d ( i , j 1 ) , d ( i 1 , j 1 ) } + 1



为什么状态会这样转移,需要画图
这里写图片描述
大概就是这样。
我做不出来的原因是因为思考的方向不对,因为之前做的 球场那道题(实际上本题也确实可以用技巧枚举做出来),就一直在想直接枚举正方形起始点不好,一直在想怎么枚举正方形的边。这只能说明, 思维定势有好有坏,但在我做题量还非常少的情况下请谨慎的使用思维定势,别一看到某道题就说是另外一道题的翻版,这样往往连正确的做法都掌握不到
另外一个原因是,缺少足够的画图与推演。图上这个道理很明显,我就不相信自己要是半小时一直勾勾画画能想不出来,但是自己一直凭空想而不去动手。只能说, 对于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;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/81003668