1.最大字段和問題
求一個序列最大連續子序列之和。
例如序列[-1,-2,-3,4,5,-6]的最大子段和為4 + 5 = 9。
①枚舉法
int MaxSum(int n,int *a){ int sum = -0x3f3f3f3f; for(int i=0;i<n;i++){ int b = 0; for(int j=i;j<n;j++){ b += a[j]; sum = b > sum ? b : sum; } } return sum; }
②動態規划
解題思路:
第一步:設b[ j ] 為 1到 j 的最大連續子序列之和。
第二步:因為b[ j ] 為以a[ j ]結尾的最大連續子序列之和,因此有兩種可能
1.b[ j ] = a[ j ]
2.b[ j ] = b[ j - 1 ] + a[ j ]
因此我們可以得到遞推方程,
b[ j ] = max{ a[ j ], b[ j - 1] + a[ j ] } = max { 0 , b[ j - 1 ]} + a[ j ]
int MaxSum(int n,int *a){ int sum = -0x3f3f3f3f, b = 0; for(int i=0; i<n; i++){ if(b>=0) b+=a[i]; else b=a[i]; if(b>sum) sum = b; } return sum; }
2.引申:兩個連續序列的最大字段和問題
求兩個等長的序列的最大重疊連續子序列之和
例,第一個序列為[-1,-2,-3,4,5,-6],第二個序列為[1,2,4,4,5,-6],則 MAX = ( 4 + 5) + (4 + 5) = 19
2與1的區別在於,原本只有一個序列,現在變成兩個,但是求的是最大重疊連序列之和,所以可以將兩個序列加起來變成一個序列。
①枚舉法
②動態規划
解題思路:
設b[ j ] 為 1到 j 的最大重疊連續子序列之和。
若b[ j - 1 ] >= 0 ,
則 b[ j ] = b [ j - 1 ] + a[ 0 ][ j ] + a[ 1 ][ j ];
否則 b[ j ] = a[ 0 ][ j ] + a[ 1 ][ j ]
int MaxSum(int n,int (*a)[6]){ int sum = -0x3f3f3f3f, b = 0; for(int i=0; i<n; i++){ if(b>=0){ b+=a[0][i]; b+=a[1][i]; } else{ b=a[0][i]; b+=a[1][i]; } if(b>sum) sum = b; } return sum; }
3.最大子矩陣之和
給定矩陣A,求其子矩陣各元素之和的最值
若將矩陣的行看作是一個個的連續序列,則與2問題不同的是,
第一,可能不只一個連續序列(矩陣的行)相加,
第二,需要枚舉子矩陣的初始行R0,和結束行R1
①枚舉法
②動態規划
//求 r0行到r1行 第i列元素的和 int sum_r(int r0, int r1, int i){ int sum = 0; for(int r=r0;r<=r1;r++) sum += a[r][i]; return sum; } //求最大子矩陣和 int MaxSum(){ int sum = -0x3f3f3f3f; for(int r0=0;r0<m;r0++){//枚舉初始行 for(int r1=r0;r1<m;r1++){//枚舉結束行 int b = 0; for(int i=0; i<n; i++){//這個循環使用問題1中的算法 if(b>=0) b+=sum_r(r0,r1,i);//第r0行到第r1行 第i列元素和 else b=sum_r(r0,r1,i); sum = sum > b? sum : b; } } } return sum; }
我們能夠注意到,上面的程序,需要我們寫一個計算第r0行到第r1行第i列的元素和的函數sum_r( ),但是我們需要頻繁調用這個函數,可以用一個數組來記錄計算結果,這一步可以在我們讀入數據的時候進行。
專門建立一個二維數組,col [ i ][ j ],記錄第 i 列,前 j 個元素的和。
所以,MaxSum函數中,b += sum_r(r0, r1, i ),可以替換成
b += col[ i ][ r1 ] - col[ i ][ r0 - 1 ]
最終代碼
int MaxSum(){ int sum = -0x3f3f3f3f; for(int r0=0;r0<m;r0++){ for(int r1=r0;r1<m;r1++){ int b = 0; for(int i=0; i<n; i++){ if(b>=0) b+=col[i][r1] - col[i][r0 - 1]; else b=col[i][r1] - col[i][r0 - 1]; sum = sum > b? sum : b; } } } return sum; }
4.最大m字段和問題