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

京公网安备 11010502036488号