tyvj 1466 最美妙的矩阵
一个链接:http://hzwer.com/1811.html
题目分析:
这是一道区间DP,但我一开始连暴力都想复杂了。(QWQ)结果连30分的暴力都没想到!!!
解法一:其实这道题的暴力应该还是蛮好想的!分别枚举两个端点(一个左上,一个右下)然后暴力扫一遍区间,看是否合法即可,然后记录最大值。
解法二:我们优化一下上述思路,我们先预处理一下。用u[i][j]记录第i行第j列的数往上单调递减的最大值,再用一个can[i][j][k]数组表示第i行到第j行中的第k列是否能和k-1列合在一起。然后就可以DP了,我们用f[i][j][k]表示从第i行到第j行中的第k列能够得到的最大面积。然后写一个if判断一下就好,具体看代码中说明。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int a[210][210],u[210][210],can[210][210][210],f[210][210][210];
int ans,n,m;
//a为原数组,用来存储输进来的值
//u[i][j]表示第i行第j列的往上单调递减的最大值
//can[i][j][k]表示第i行到第j行中的第k列能否满足要求
//f[i][j][k]表示第i行到第j行中的第k列的子矩阵的最大面积
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(a[i][j]>=a[i-1][j]) u[i][j]=u[i-1][j]+1;
else u[i][j]=1;
for(int i=1;i<=n;++i)
for(int j=i;j<=n;++j)
for(int k=1;k<=m;++k)
if((can[i][j-1][k]||j-1<i)&&j-i+1<=u[j][k]&&a[j][k]>=a[j][k-1])
//(can[i][j-1][k]||j-1<i)这个条件是表示前一行可以满足要求或者当前j等于i时都可以
//j-i+1<=u[j][k],在第j行第k列的位置上往上的单点递减区间长度得大于等于j-i+1
//a[j][k]>=a[j][k-1],同行之间也要满足单调递增
can[i][j][k]=1;
for(int i=1;i<=n;++i)
for(int j=i;j<=n;++j)
for(int k=1;k<=m;++k) {
if(can[i][j][k]) f[i][j][k]=f[i][j][k-1]+j-i+1;
//如果满足条件,那么就更新,这里在原来数组的基础上加上j-i+1,
//表示的是现在第i行到第j行的第k列可以加入进去
else if(u[j][k]>=j-i+1) f[i][j][k]=j-i+1;
//不能的话,如果u[j][k]>=j-i+1那就值赋值这一个单位宽度的区间面积
ans=max(ans,f[i][j][k]);//去一个最大值
}
printf("%d",ans);
return 0;
}