最大子段和问题:
如果有一个一维数组a[n],如何找出连续的一段,使其元素之和最大呢
1.穷举法
2.动态规划
我们另b[i-1]表示以a[i-1]结尾的最大子段和,那么b[i]只有两种情况b[i-1] + a[i]和a[i],我们取二者最大的,即b[i] = max(b[i -1] + a[i],a[i])(状态转移方程)
代码如下:
int MaxSubArray(int a[],int n)
{
int i,b = 0,sum = 0;//b记录前一个最大子段和,sum记录最大子段和
for(i = 0;i < n;i++)
{
if(b + a[i] > a[i])
b += a[i];
else
b = a[i];
if(b > sum)
sum = b;
}
return sum;
}
最大子矩阵问题
说了这么多,这跟最大子矩阵有什么关系呢?当然有关系学啦!二维就是一维的扩展,把二维压扁不就变成一维了吗?
我们假设所求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]} ,现在我们可以看出,这其实就是一个一维数组的最大子段问题。如果把二维数组看成是纵向的一维数组和横向的一维数组,那问题不就迎刃而解了吗?把二维转换成了我们刚刚解决了的问题。
蓝桥杯的最大子矩阵的题:最大子矩阵
代码如下:
#include <iostream>
#include <string.h>
using namespace std;
long long MaxSub(long long arr[],int n){
long long b = 0;
long long sum = -1000000000;
for(int i = 0;i < n;i++){
if(b + arr[i] < arr[i]){
b = arr[i];
}else{
b = b + arr[i];
}
if(sum < b){
sum = b;
}
}
return sum;
}
long long rec[510] = {0};
int tab[510][510] = {0};
int main(){
int n,m;
cin>>n>>m;
for(int i = 0;i < n;i++){
for(int j = 0;j < m;j++){
int t;
cin>>t;
tab[i][j] = t;
}
}
long long maxx = -100000000;
for(int i = 0; i < n;i++){
memset(rec,0,sizeof(rec));
for(int j = i; j < n;j++){
for(int k = 0;k < m;k++){
rec[k] += tab[j][k];
}
long long t = MaxSub(rec,m);
if(t > maxx){
maxx = t;
}
}
}
cout<<maxx;
return 0;
}