【動態規划】最大連續子序列和,最大子矩陣和,最大m子段和


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字段和問題

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM