最大子段和、最大子矩阵和

最大子段和

Description

给出n个整数序列(可能为负数)组成的序列a1a2, ..., an,求该序列形如的子段和的最大值。当所有整数均为负数时,定义最大子段和为0。

Input

多测试用例。每个测试用例占2行:

第一行是序列的个数n(0 < n ≤ 10000),第二行是n个整数。

Output

为每个测试用例输出一行结果:最大子段和。

Sample Input

6
-2 11 -4 13 -5 -2
3
1 2 3

Sample Output

20
6

问题分析

很经典的dp问题,用dp[i]表示前i个数的最大子段和

每次选择第i个数的时候判断前i-1个数的最大子段和是否为负,为负则舍去,为正就加上

状态转移方程 dp[i]=max(dp[i-1],0)+dp[i]

记录dp[i]的最大值

代码实现

#include<iostream>
#include<cstring>
using namespace std;
#define MAX_DATA 10000
#define INF 0x3f3f3f3f
int a[MAX_DATA];
int dp[MAX_DATA];
int main()
{
    int n;
    while(cin>>n){
        for(int i=1;i<=n;++i){
            cin>>a[i];
        }
        memset(dp,0,sizeof(dp));//初始化
        int ans=-INF;
        for(int i=1;i<=n;++i){
            dp[i]=max(dp[i-1],0)+a[i];
            ans=max(ans,dp[i]);//记录最大值
        }
        cout<<ans<<endl;
    }
    return 0;
}

最大子矩阵和

Description

给出一个m×n的矩阵,请输出它的最大子矩阵和。

Input

多测试用例,每个测试用例:

第一行是两个正整数m和n,表示该矩阵的行数和列数。1 < m, n < 400

接下来m行,每行n个整数,空格分隔。

Output

每个测试用例输出一行:该矩阵的最大子矩阵和。运算结果在int范围内。

Sample Input

4 4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2

Sample Output

15

问题分析

用一个二维数组存储每列的前缀和,即a[i][j]表示第j列前i行的和

之后就可以转换为一维的最大子段和问题

代码实现

#include<iostream>
#include<cstring>
using namespace std;
#define MAX_DATA 400
#define INF 0x3f3f3f3f
int a[MAX_DATA+2][MAX_DATA+2];
int dp[MAX_DATA+2][MAX_DATA+2];
int main()
{
    int m,n,x;
    while(cin>>m>>n){
        memset(a,0,sizeof(a));
        for(int i=1;i<=m;++i){
            for(int j=1;j<=n;++j){
                cin>>x;
                a[i][j]=a[i-1][j]+x;//存储每列前i行的和
            }
        }
        memset(dp,0,sizeof(dp));//初始化
        int ans=-INF;
        for(int i=1;i<=m;++i){
            for(int k=0;k<i;++k){//遍历第k行到第i行
                for(int j=1;j<=n;++j){
                    dp[i][j]=max(dp[i][j-1],0)+a[i][j]-a[k][j];//最大子段和表示第k行到第i行的最大子矩阵
                    ans=max(ans,dp[i][j]);
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Initial-C-/p/13719934.html