题目来源:http://noi.openjudge.cn/ch0206/1768/
1768:最大子矩阵
总时间限制: 1000ms;内存限制: 65536kB
- 描述:
- 已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵。
比如,如下4 * 4的矩阵 - 0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2 - 的最大子矩阵是
- 9 2
-4 1
-1 8 - 这个子矩阵的大小是15。
- 输入:
- 输入是一个N * N的矩阵。输入的第一行给出N (0 < N <= 100)。再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。已知矩阵中整数的范围都在[-127, 127]。
- 输出:
- 输出最大子矩阵的大小。
- 来源
- 翻译自 Greater New York 2001 的试题
- ————————————————————————————————————————————————
- 刚拿到这道题的时候是有点懵逼的,因为对于二维结构想不到最优子结构,更想不到状态转移方程。
- 但是既然二维有困难,那么我们可以先把它转化为一维的结构。
-
铺垫:先想如何找一行一维数组的最大连续元素和呢?重点是这个状态转移方程: b[i] = max { b[i-1] + b[i] , b[i] };
若到前一个元素为止的“最优的”累加和为正,则计算到当前元素的累加和时,需要加上先前的部分;反之则不。
现在我们来想怎么把二维压缩到一维:
矩阵内的元素为左上角的坐标(x1,y1)和右下角的坐标(x2,y2)决定。
如果我们暂时定下来目前是找 x1,x2 之间的,垂直长度已为|x2-x1|的矩形的最大面积;
那么既然宽度|x2-x1| 已经定下来了,那么这边枚举出来的矩阵面积,必定是某几连续列的整列和。
把每列的元素和都加起来,a[ym,x1]+……a[ym,x2],即得到了一个一维数组。
再按照前面的铺垫,找到最大最大字段和,即为在|x2-x1|宽度约束下的最大矩形
外面再套两层for循环来枚举不同的 x1,x2 即可
以下是AC代码:
1 #include <iostream> 2 #include <cmath> 3 using namespace std; 4 5 int a[105][105]; 6 int b[105]; //算出目前x1-x2行的二维压缩成的一维数组 7 8 int main(){ 9 int N; 10 cin>>N; 11 for(int i=0;i<N;i++){ 12 for(int j=0;j<N;j++){ 13 cin>>a[i][j]; 14 } 15 } 16 int ans=0; 17 for(int i=0;i<N;i++){ 18 for(int j=i;j<N;j++){ 19 memset(b,0,sizeof(b)); 20 for(int p=0;p<N;p++){ 21 for(int q=i;q<=j;q++){ 22 b[p]+=a[q][p];//得到压缩后的一维数组 23 } 24 } 25 for(int k=0;k<N;k++){ 26 b[k]=max(b[k],b[k]+b[k-1]); 27 } 28 for(int k=0;k<N;k++){ 29 ans=max(ans,b[k]); 30 } 31 } 32 } 33 34 cout<<ans<<endl; 35 36 return 0; 37 }
参考博客:https://www.cnblogs.com/GodA/p/5237061.html
原文地址:https://www.cnblogs.com/Accepted20191024/p/11745232.html
时间: 2024-10-15 04:14:05