子段与子段和的概念:
给定一个由数字组成的序列,其中一段连续的序列称为一个子段(假设非空),子段中所有的数字和就是为 子段和
例子:
{1,2,3,4} ,
连续子段有 {1} {1,2} {1,2,3} {1,2,3,4} {2,3} {2,3,4} {3,4} {4}
O(n2) 枚举的做法:
for(int i=0;i<n;++i){ long sum = 0; for(int j=i;j<n;++j){ sum += a[j]; if(sum > nMax){ nMax = sum; } } }
通过观察发现。
(1) 整个序列都是负数,那么 最大子段和 为 最小的负数 。
(2) 如果都是正数,那么 最大子段和 就是 整个序列的的和。
(3) 如果有正有负,那么 最大的子段和 >= 整个序列的最大值,
那么我们可以假设一个变量sum = 0; 来记录当前的子段和。
ans 记为 整个序列的最大值
因为要得到最大的子段 假设{ n1,n2,n3 },那么这个子段前缀 {n1,n2} 一定不会 < 0
要得到 更大的子段和,我们就不会用 < 0 的子段和 来 拖累 后面的子段和。
用 ans = max(ans , sum)。来求出结果
O(n) 动态规划实现代码:
#include <iostream> #include <algorithm> using namespace std; const int inf = 0x7fffffff; int num[101]; int main() { int N; cin >> N; for(int i=0;i<N;i++){ cin >> num[i]; } int ans = -inf; for(int i=0;i<N;i++){ ans = max(ans,num[i]); } if(ans <= 0){ cout << ans << endl; }else{ int sum =0; for(int i=0;i<N;i++){ if(sum + num[i] < 0){ sum = 0; }else{ sum += num[i]; } ans = max(ans,sum); } cout << ans << endl; } return 0; }
题目:
题解:
#include <iostream> #include <algorithm> using namespace std; int a[1001]; int dp [1001]; const int INF = 0x3f3f3f3f; int main(){ int n; while(cin >> n&& n){ for(int i=0;i<n;++i){ cin >> a[i]; } for(int i=0;i<n;++i){ dp[i] = a[i]; for(int j=0;j<i;++j){ if(a[i] > a[j]){ dp[i] = max(dp[j] + a[i],dp[i]); } } } int maxN = a[0]; for(int i=0;i<n;++i){ maxN = max(maxN,dp[i]); } cout << maxN << endl; } return 0; }