洛谷P2008做题总结

题目链接

1 问题分析

适合用动态规划算法解决的问题需要满足:拥有最优子结构并且问题无后效性这两个条件。接下来,笔者将分析本题是否满足上述两个条件:

1.1 最优子结构

对于第一个数,其最长不下降子序列是1(它自己)。求第i个数(i>1)的最长不下降子序列,我们可以先找满足不大于第i个数的数,之后在这些满足条件的数里面找到最长的序列的长度,加1(要把第i个数也加进去),就可以得到第i个数的最长不下降子序列的长度。这样看,第i(i>1)个数的最长不下降子序列可以从前i-1个数的最长不下降子序列得到答案,而且是第1个数也是有答案的,满足最优子结构。

1.2 无后效性

通过1.1的分析,我们知道第一个数的最长不下降子序列是1;从第二个数起,其最长不下降子序列都源于前面i-1个数的最长不下降子序列,故无后效性,可以使用动态规划求解。

2 解题思路

我们可以从前往后依次确定每个数的最长不下降子序列长度,并求和。

2.1 存储结构

为此我们可以开三个数组:a,f,v。a数组用来存储每个数的值;f数组存储每个数的最长不下降子序列的长度;v数组存储最长不下降子序列中所有数的和。

2.2 判断条件及执行过程

在这里有一点需要注意的是,题目说了“如有多个最长不下降子序列,那么取编号字典序最小的”,所以,1.在遍历前面的数的顺序时应该从前往后遍历;2.在判断条件上,我们除了要判断前面的数小于等于当前的数之外,还有判断前面的数的最长不下降子序列长度+1是否大于当前数原本的最长不下降子序列长度。如果是,更新当前数最长不下降子序列的长度与所有数的和,这个在f和v中更新相应的元素,否则就在看后一个数的情况。用这两个条件可以找到最长的不降子序列并且字典序最小。

2.3 f和v数组的初始化

抛开题目测试数据的样例,我们看一下,如果n=5,给的是5,4,3,2,1的话,最后应该输出5,4,3,2,1。若2.2的判断语句用单分支结构实现,那么每一次执行循环体不满足条件,所以f和v中相应的元素都没有变化,等于初始值。根据数据特点,我们可以把f中的元素初始化为1;将a中的元素初始化时赋给v数组。

3 AC代码

#include<bits/stdc++.h>
using namespace std;
int f[10001],a[10001];
int v[10001];
int n;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		f[i]=1;
		v[i]=a[i];
	}
	for(int i=2;i<=n;i++){
		for(int j=1;j<=i-1;j++){
			if(a[j]<=a[i]&&f[i]<f[j]+1){
				f[i] = f[j]+1;
				v[i] = v[j]+a[i];			
			}
		}
	}
	for(int i=1;i<=n;i++)
		cout<<v[i]<<" ";
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值