zoukankan      html  css  js  c++  java
  • 题解+新技巧--一本通1282:最大子矩阵

    http://ybt.ssoier.cn:8088/problem_show.php?pid=1282(题目传送)

    虽然已知是DP,但第一眼看挺蒙的,想了想后设了个a[i][j][k][l]表示长(坐标)为i~j,宽(坐标)为k~l的矩阵,但根本找不到状态转移方程啊。后借鉴题解(https://www.cnblogs.com/GodA/p/5237061.html)后领悟到的另一种方法:

    任何问题都有它的简化,看到二维,没办法时我们可以考虑一下一维:求一维数组的一个最大连续段,我们可以设b[i]为从前i个数的最大连续段(a[i]为一开始存入的输入数据),b[i]无非就有两种情况:以它结尾的最大连续段;或以它开头另开一个最大连续段(当b[i-1]小于0时b[i-1]+a[i]反而比a[i]小,因此不如新开一个最大连续段)。

     1 int MaxSubArray(int a[],int n)
     2 {
     3     int i,b = 0,sum = 0;
     4     for(i = 0;i < n;i++)
     5     {
     6         if(b>0)                // 若a[i]+b[i-1]会减小
     7             b += a[i];        // 则以a[i]为首另起一个子段
     8         else    
     9             b = a[i];
    10         if(b > sum)    
    11             sum = b;
    12     }
    13     return sum;
    14 }

    想完一维,跟二维有什么关系?当然有了,我们把二维“拍”成一维,不就行了吗?

    我们假设所求N*N的矩阵的最大子矩阵是从i列到j列,q行到p行,如下图所示(假设下标从1开始)

      a[1][1]  a[1][2]  ······  a[1][i]  ······  a[1][j]   ······  a[1][n]

      a[2][1]  a[2][2]  ······  a[2][i]  ······  a[2][j]   ······  a[2][n]

                      ······

      a[q][1]  a[q][2]  ······  a[q][i]  ······  a[q][j]  ······  a[q][n]

                      ······

      a[p][1]  a[p][2]  ······  a[p][i]  ······  a[p][j]  ······  a[p][n]

                      ······

      a[n][1]  a[n][2]  ······  a[n][i]  ······  a[n][j]  ······  a[n][n]

      最大子矩阵就是图示红色部分,如果把最大子矩阵同列的加起来,我们可以得到一个一维数组{a[q][i]+······+a[p][i] , ······ ,a[q][j]+······+a[p][j]} ,现在我们可以看出,这其实就是一个一维数组的最大子段问题:

    分别将各个高的矩阵压缩成一个一维数组并求它的最大连续段,则在二维的体现就是一个相应高的最大连续矩阵,取所有相应最大连续矩阵的最大值,就是答案(还好题目只要求最大值,不要求给出最大矩阵是什么)

    AC代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 int dp[101][101],arr[101];
     6 int maxsub(int a[],int n)
     7 {
     8     int max=0,b=0;
     9     for(int i=0;i<=n;i++)
    10     {
    11         if(b>0)
    12             b+=a[i];
    13         else
    14             b=a[i];
    15         if(b>max) max=b;
    16     }
    17     return max;
    18 }
    19 int main()
    20 {
    21     int n,maxx=0;
    22     cin>>n;
    23     for(int i=1;i<=n;i++)
    24         for(int j=1;j<=n;j++)
    25             cin>>dp[i][j];
    26     for(int i=1;i<=n;i++)
    27     {
    28         memset(arr,0,sizeof(arr));
    29         for(int j=i;j<=n;j++)
    30         {
    31             for(int k=1;k<=n;k++)
    32             arr[k]+=dp[j][k];
    33             int m=maxsub(arr,n);
    34             if(maxx<m)
    35             maxx=m;
    36         }
    37     }
    38     cout<<maxx;
    39     return 0;
    40 }

    最后总结一下:1.对问题的简化(二维转一维,模拟转整体充分条件(长方体),无序转有序等)十分重要!

    2.线型动态规划多以结尾为状态。

  • 相关阅读:
    python3全栈开发-并发编程的多进程理论
    python3全栈开发-补充UDP的套接字、操作系统、并发的理论基础
    python3全栈开发-什么是粘包、粘包现象、如何解决粘包
    python3全栈开发-socket编程
    python3全栈开发- 元类metaclass(面试必考题)
    浏览器窗口
    SQL 笔记
    数据库连接字符串
    获取网卡地址信息
    启动所选择的应用程序
  • 原文地址:https://www.cnblogs.com/InductiveSorting-QYF/p/10503140.html
Copyright © 2011-2022 走看看