动态规划

题意:

链接:https://ac.nowcoder.com/acm/problem/14294
来源:牛客网

给定一个n*m的矩阵,矩阵元素由X和O构成,请求出其中最大的由X构成的蝴蝶形状。
由X构成的蝴蝶形状的定义如下:
存在一个中心点,并且其往左上、左下、右上、右下四个方向扩展相同的长度(扩展的长度上都是X),且左上顶点与左下顶点、右上顶点与右下顶点之间的格子全由X填充。我们不在意在蝴蝶形状内部是X还是O。
例如:
XOOOX
XXOXX
XOXOX
XXOXX
XOOOX
是一个X构成的蝴蝶形状。
X
也是。

XOOX
OXXO
OXXO
XOXX
不是(不存在中心点)。

输入描述:
第一行两个整数n, m表示矩阵的大小(1 <= n, m <= 2000);
接下来n行,每行一个长度为m的字符串表示矩阵,矩阵元素保证由X和O构成。
输出描述:
一行一个整数表示最大的由X构成的蝴蝶形状的对角线的长度。
示例1
输入
复制
5 5
XOOOX
XXOXX
XOXOX
XXOXX
XOOOX
输出
复制
5

分析

这题是动态规划,我们可以很清楚的发现直接做是做不出来的。找不到转移状态。
那么我们可以分解这个问题
我们记
a[i][j]为(i,j)向右下延伸的最长距离
b[i][j]为(i,j)向下延伸的最长距离
c[i][j]为(i,j)向左下延伸的最长距离

另外我们还发现,他的外接矩形一定是一个奇数长的正方形!!

则,问题简单了:
我们可以利用动态规划轻易的计算出a,b,c
再对左上顶点进行枚举
根据a,b找到右上顶点,再进行判断是否可以构成蝴蝶

其实,我没有做出来。。。。。。看了人家的题解后恍然大悟!!

面向结果编程。。。。

#include<iostream>
#include<algorithm>
using namespace std;
const int max_n = 2000 + 100;
char chs[max_n][max_n];
int a[max_n][max_n], b[max_n][max_n], c[max_n][max_n];
int ans = 0;

int main() {
    ios::sync_with_stdio(0);
    int n, m;cin >> n >> m;
    for (int i = 1;i <= n;i++)
        for (int j = 1;j <= m;j++)
            cin >> chs[i][j];
    for (int i = n;i > 0;i--)
        for (int j = m;j > 0;j--)
            if (chs[i][j] == 'X') {
                a[i][j] = a[i + 1][j + 1] + 1;
                b[i][j] = b[i + 1][j] + 1;
                c[i][j] = c[i + 1][j - 1] + 1;
            }
    for (int i = 1;i <= n;i++) {
        if (n - i + 1 <= ans)break;
        for (int j = 1;j <= m;j++) {
            if (m - j + 1 <= ans)break;
            int k = min(a[i][j], b[i][j]);k--;
            if (k & 1)k--;
            while (k + 1) {
                if (k + 1 <= ans)break;
                int cmp = min(b[i][j + k], c[i][j + k]);
                if (cmp >= k) { ans = k + 1;break; }
                k -= 2;
            }
        }
    }cout << ans << endl;
}

这道题,动态规划的部分难点并不是在找转移方程,难点在于找状态。
我实在是没有想到,竟然可以使用多个动态规划方程数组,进行答案的组合!!!!
触及到思维盲区了,但其实仔细想想,这也是枚举的常规思路?