题目概述
给定N个数构成的序列,求严格上升子序列中元素和的最大值
时限
1000ms/2000ms
输入
每行第一个正整数N,其后N个整数,为序列中的数,输入到N=0为止
限制
1<=N<=1000;序列中的数皆在32位整型范围内
输出
每行一个数,所求的和的最大值
样例输入
3 1 3 2
4 1 2 3 4
4 3 3 2 1
0
样例输出
4
10
3
讨论
dp,最大上升子序列和,阶段,遇到的每一个数,状态,以该数结尾的上升子序列和,决策,将其加入之前某子序列的和,或以自身作为新序列,子问题,以遇到的数结尾的上升子序列和,子问题边界,以第一个数结尾的上升子序列和,无后效性确认,之前选择的数只能影响到自己为止的上升子序列和,确定参数,上升子序列和,子序列结尾的数,遇到的数自身,注意到这是一个带条件的dp,需要大于结尾的数才能加和,因而可能无法从上一阶段直接得到现阶段的解,需要考虑之前所有阶段的解并取最大者,加上自身作为自身的最优解,因而需要一个一维数组记录之前阶段的最优解,该数组为dp,基本思路便是如此,下面处理细节问题
题目要求必须是严格上升子序列,故需要修改条件,至此,思路已经明了,可以出代码了
题解状态
31MS,1720K,628B,C++
题解代码
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 1003
#define memset0(a) memset(a,0,sizeof(a))
int nums[MAXN], dp[MAXN];//存放每个数自身 存放上升子序列的和
int fun(int N)
{
int most = 0;//初始化最大和
for (int p = 0; p < N; p++) {
scanf("%d", &nums[p]);//input
dp[p] = nums[p];//初始化dp为自身 因为无法在之后完成此步骤 同时由于这一步 不再需要额外清零dp数组
for (int i = p; i >= 0; i--)
if (nums[p] > nums[i])//限制条件 大于子序列最后一个元素
dp[p] = max(dp[p], dp[i] + nums[p]);//转移方程
most = max(most, dp[p]);//记录最大上升子序列和
}
return most;
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);
int N;//元素个数
while (~scanf("%d", &N) && N)
printf("%d\n", fun(N));//output
}
EOF