Dp_关于最大子矩阵的问题总结

  我们知道子一行也是矩阵,只不过是特殊情况,首先来一道题,hdu 1506 

高度h[i]  我们定义两个数组,分别为向左扩展能到的最左边的下标,和向右扩展能到的最右边的下标。

然后两个数组分别从正方向和反反向扫一遍

#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
LL num[100005];
LL l[100005],r[100005]; int main() { int n;
    LL ans; for(;scanf("%d",&n),n;) { for(int i=1;i<=n;++i) scanf("%I64d",&num[i]);
        num[0]=num[n+1]=-1; for(int i=1;i<=n;++i) l[i]=r[i]=i;
        //dp,根据之前拓展的l,r再拓展,可以提高效率
 for(int i=1;i<=n;++i)
            //第i个高度拓展,h[j]>=h[i]的最小j
 for(;num[l[i]-1]>=num[i];)
               l[i]=l[l[i]-1]; for(int i=n;i>=1;--i)
            //第i个高度拓展,h[j]>=h[i]的最大j
 for(;num[r[i]+1]>=num[i];)
               r[i]=r[r[i]+1];
        ans=0; for(int i=1;i<=n;++i) if(ans<num[i]*(r[i]-l[i]+1))
               ans=num[i]*(r[i]-l[i]+1);
        printf("%I64d\n",ans); } return 0; }

现在特殊情况考虑完了以后,我们考虑正常矩阵

hdu 1505

这次定义一个Up数组从上往下扫描,相当于矩阵的压缩,于是每次只要对一行的Up进行处理,相当于就转换成了第一个问题特殊情况:一行的矩阵

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<ctype.h>
using namespace std;
#define oo 0x3f3f3f3f
#define maxn 1010
int Up[maxn][maxn]; int L[maxn], R[maxn]; char map[maxn][maxn]; int main() { int T, n, m, ans; char val[5];
    scanf("%d", &T); while (T--) {
        scanf("%d %d", &n, &m); for (int i = 1; i <= m; i++)
            Up[0][i] = 0; for (int i = 1; i <= n;i++) for (int j = 1; j <= m; j++) {
            scanf("%s", &val); if (val[0] == 'F')
                Up[i][j] = Up[i - 1][j] + 1; else
                Up[i][j] = 0; }
        ans = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++)
                L[j] = R[j] = j;

            Up[i][0] = Up[i][m + 1] = -1; for (int j = 2; j <= m; j++) while (Up[i][L[j] - 1] >= Up[i][j])
                L[j] = L[L[j] - 1]; for (int j = m - 1; j >= 1;j--) while (Up[i][R[j] + 1] >= Up[i][j])
                R[j] = R[R[j] + 1]; for (int j = 1; j <= m; j++)
                ans = max(ans, Up[i][j] * (R[j] - L[j] + 1)); }
        printf("%d\n", ans * 3); } return 0; }
/*
1.00
3.71
0.04
5.19
0.00
*/
在以上基础加条件的

hdu 2870 题目加点要求就是允许将某个字母变成某个字母

这样只要将字母变成对应的字母,然后对每种变换进行一次dp,找到其中最大的值,其实情况只要3三种就ok了,贪心思想:尽量让所有的字母变成a,b,c这样只要对a,b,c的情况dp就ok了。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<ctype.h>
using namespace std;
#define oo 0x3f3f3f3f
#define maxn 1010
int Up[maxn][maxn]; int L[maxn], R[maxn]; char map[maxn][maxn]; bool ok[4][30]; void Solve() {
    memset(ok, 0, sizeof ok);
    ok[0]['a' - 'a'] = 1;
    ok[0]['w' - 'a'] = 1;
    ok[0]['y' - 'a'] = 1;
    ok[0]['z' - 'a'] = 1;

    ok[1]['w' - 'a'] = 1;
    ok[1]['x' - 'a'] = 1;
    ok[1]['z' - 'a'] = 1;
    ok[1]['b' - 'a'] = 1;

    ok[2]['x' - 'a'] = 1;
    ok[2]['y' - 'a'] = 1;
    ok[2]['z' - 'a'] = 1;
    ok[2]['c' - 'a'] = 1; } int main() {
    Solve(); int n, m, ans; while (scanf("%d %d", &n, &m) != EOF) { for (int i = 1; i <= m; i++)
            Up[0][i] = 0; for (int i = 1; i <= n; i++)
            scanf("%s", map[i] + 1);

        ans = 0; for (int k = 0; k < 3; k++) { for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (ok[k][map[i][j] - 'a'])
                    Up[i][j] = Up[i - 1][j] + 1; else
                    Up[i][j] = 0; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++)
                    L[j] = R[j] = j;

                Up[i][0] = Up[i][m + 1] = -1; for (int j = 2; j <= m; j++) while (Up[i][L[j] - 1] >= Up[i][j])
                    L[j] = L[L[j] - 1]; for (int j = m - 1; j >= 1; j--) while (Up[i][R[j] + 1] >= Up[i][j])
                    R[j] = R[R[j] + 1]; for (int j = 1; j <= m; j++)
                    ans = max(ans, Up[i][j] * (R[j] - L[j] + 1)); } }
        printf("%d\n", ans); } return 0; }
/*
1.00
3.71
0.04
5.19
0.00
*/
现在稍微再改变下

hdu 2830 题目要求可以交换任意列任意次,一开没想到怎么做,看了题解发现,只要对每次的行进行列的排序,然后枚举列大到小的长度,这样就可以找出最大的值。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<ctype.h>
using namespace std;
#define oo 0x3f3f3f3f
#define maxn 1010
int up[2][maxn]; int res[maxn]; char map[2][maxn]; int main() { int n, m, ans; while (scanf("%d %d", &n, &m) != EOF) {
        memset(up, 0, sizeof up);
        ans = 0; for (int i = 1; i <= n; i++) {
            scanf("%s", map[i % 2] + 1); for (int j = 1; j <= m; j++) { if (map[i % 2][j] == '1')
                    up[i % 2][j] = up[(i - 1) % 2][j] + 1; else
                    up[i % 2][j] = 0; }

            memcpy(res, up[i % 2], sizeof res);
            sort(res + 1, res + 1 + m); for (int j = 1; j <= m; j++)
                ans = max(ans, (m - j + 1)*res[j]); }
        printf("%d\n", ans); } return 0; }
/*
1.00
3.71
0.04
5.19
0.00
*/

你可能感兴趣的:(dp,HDU)