注解
1、用动态规划方法解决最大子列和问题。关键是设置一个dp[]数组,dp[i]表示以i结尾的最大子列和。
如dp[0]表示以0作为结尾的最大子列和,dp[1]表示以1作为结尾的最大子列和。
因此,要求出整个序列的最大子列和,只需要从头到尾遍历dp,找出最大值。这是最原始的最大子列和问题的解法。
2、本题除了要求输出最大和,还要求输出起始位置和终止位置。这就要在dp[]数组的基础上,再增加start[]数组,start[i]表示以i作为结束的最大和的起始位置。
3、动态规划的核心:找出状态转移方程:dp[i] = max(a[i], dp[i-1]+a[i])。
本质就是,如果dp[i-1]>=0,dp[i]就等于dp[i-1]+a[i]。如果dp[i-1]<0,就输出a[i]。
4、一个小的注意点:初始化。题目不保证所有数字都是非负数,因此初始化答案时,应该是用第一个数字初始化。而不能简单用一个负数。因为可能出现所有数字都比这个负数小的情况,这样这个负数就会被误当成最终答案而输出。
代码
#include <iostream>
#include <string.h>
using namespace std;
const int MAX = 100001;
int a[MAX];
int dp[MAX];
int start[MAX];
void process(int len){
dp[0] = a[0];
start[0] = 0;
for(int i=1; i<len; i++){
if(a[i]>dp[i-1]+a[i]){
dp[i] = a[i];
start[i] = i;
}
else{
dp[i] = dp[i-1]+a[i];
start[i] = start[i-1];
}
}
}
int main() {
int T;
cin>>T;
for(int i=1; i<=T; i++) {
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
memset(start, 0, sizeof(start));
int n;
cin>>n;
for(int j=0; j<n; j++) {
cin>>a[j];
}
process(n);
int max = dp[0];
int ansStart = 1;
int ansEnd = 1;
for(int j=1; j<n; j++){
if(dp[j]>max){
max = dp[j];
ansStart = start[j]+1;
ansEnd = j+1;
}
}
cout<<"Case "<<i<<":"<<endl;
cout<<max<<" "<<ansStart<<" "<<ansEnd<<endl;
if(i<T){
cout<<endl;
}
}
return 0;
}