最大子段和、最大子矩阵和
最大子段和
Description
给出n个整数序列(可能为负数)组成的序列a1, a2, ..., 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; }