最大上升子序列之和
题目中已告诉最长上升子序列之和!=最大上升子序列之和
动态规划的比较重要的点
1. 拆分成子问题
2. 状态转移方程
(其实动态规划也可以理解为递归的逆过程)
根据这道题来实操一下
-
拆分成子问题
求的是n个数的最大上升子序列之和
则可以拆分成求n-1个数的最大上升子序列之和
以此类推 最后是先求1个数的最大上升子序列之和
//这里是做题自己想
(这里有没有一点递归的味道,1为返回条件)
从求当一个数时到求当两个数时的最大上升子序列之和
以此类推,最后由求当n-1时到当n时的最大上升子序列之和
//这里是程序进行求解
(有没有递归返回去的味道) -
状态转移方程
状态转移方程,是连接两个状态的桥梁
可能这样说比较抽象,结合这道题来理解一下
求当一个数时到求当两个数时的最大上升子序列之和,再到三个数时
简单模拟一下
这里有两个数组int ans[1000+10]={0,1,50,20,72};//存储和 int m[1000+10]={0,1,50,20,72};//存数的序列
假设
这四个数是:1 50 20 72
求一个数时 自然和为1;
那么ans[1]=1;
两个数时
首先要判断是不是上升序列
这里是true,和为50+1;
ans[2]==ans[1]+m[2]==21;//原本ans[2]=50;
三个数时
m[1]与m[3]能成为上升序列—>ans[3]=ans[1]+ans[3]//ans[3]原本为20
四个数时
m[4]与m[2]能成为上升序列—>ans[4]=ans[2]+m[4]
总结一下
如果是上升序列,比较(当前值m+序列前一个数的上升子序列的和ans,当前值ans)
不能比较成m+ans,m;
- 从数据的角度出发相加一定大于原数,会导致最终答案错误
- 从处理时的角度出发,如果盲目的先加前面的数,会导致后面应该加的更大的数加不了
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n;
long long ans[1000+2];
int m[1000+2];
int main(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>m[i];
ans[i]=m[i];//因为求的是最大上升子序列之和,所以他本身为一个数的时候,最大上升子序列和为他本身
}
for(int i=2;i<=n;++i)
for(int j=1;j<i;++j)//首先要满足是以i为终点的值大于j的值,保证是上升子序列
if(m[i]>m[j]) ans[i]=max(ans[i],m[i]+ans[j]);//比较目前以i为终点上升子序列之和的值,和以j为终点的值+i的值
//谁大谁为最大上升子序列之和的值
sort(ans+1,ans+1+n);
cout<<ans[n];
return 0;
}
解释不佳,还请指出
解释有误,还请纠正