【c++动态规划】最长上升序列

问题 B: 最长上升序列

时间限制: 1 Sec  内存限制: 128 MB

题目描述

       设有由n个不相同的整数组成的数列,记为:b(1)、b(2)、……、b(n)且b(i)<>b(j)  (i<>j),若存在i1<i2<i3< … < ie 且有b(i1)<b(i2)< … <b(ie)则称为长度为e的上升序列。程序要求,当原数列出之后,求出最长的上升序列。

       例如13,7,9,16,38,24,37,18,44,19,21,22,63,15。例中13,16,18,19,21,22,63就是一个长度为7的上升序列,同时也有7 ,9,16,18,19,21,22,63长度为8的上升序列。

输入

一行,若干个整型数(长度不超过1000)。

输出

输出最长的上升序列

样例输入

13 7 9 16 38 24 37 18 44 19 21 22 63 15

样例输出

8

【参考书目:信息学奥赛一本通】

自己对书上的程序的注释进行了补充,如果想了解详细思路可以看书的第329页

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n=0,i=0,b[10][5000];
	//b[1][i]储存这个数是多少,
	//b[2][i]储存从i位置到n的最长不下降序列长度,
	//b[3][i]储存从i位置开始最长不下降序列的下一个位置,如果=0则表示后面没有连接项 
	while(cin>>b[1][++i])
	{
		n++;//总数 
		b[2][i]=1;b[3][i]=0;
	}
	for(i=n-1;i>=1;i--)//从倒数第二个数找 (子序列开头) 
	{
		int l=0,k=0;//长度,位置 (每次新找一个数作为子序列的开头时要清零,第二个if才能执行) 
		for(int j=i+1;j<=n;j++)
		{
			if((b[1][j]>b[1][i])&&(b[2][j]>l))//如果下一个数>上一个数,且长度创新高 
			{
				l=b[2][j];k=j;//更新 
			}
			if(l>0)//状态转移
			{
				b[2][i]=l+1;//i位置到n的最长不下降序列长度+1,因为之前连上一个数了 
				b[3][i]=k;//转移到下个数的位置 
			}
		}
	}
	int k=1;
	for(int j=1;j<=n;j++)//把每个数扫一遍,看以哪个数开头的上升序列最长 
	{
		if(b[2][j]>b[2][k])	k=j;
	}
	cout<<b[2][k]<<endl;
	return 0;//完结撒花 
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 最长上升子序列(Longest Increasing Subsequence, LIS)是指一个序列最长的严格递增子序列长度。以下是 C++ 实现 LIS 的示例代码: ```c++ #include <iostream> #include <algorithm> #include <vector> using namespace std; int main() { vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18}; vector<int> dp(nums.size(), 1); // dp[i] 表示以 nums[i] 结尾的最长上升子序列长度 int res = 1; // 记录最大长度 for (int i = 1; i < nums.size(); i++) { for (int j = 0; j < i; j++) { if (nums[j] < nums[i]) { dp[i] = max(dp[i], dp[j] + 1); // 状态转移方程 } } res = max(res, dp[i]); } cout << res << endl; // 输出最长上升子序列长度 return 0; } ``` 该代码的时间复杂度为 O(n^2),可以通过二分查找优化到 O(nlogn)。 ### 回答2: 最长上升子序列(Longest Increasing Subsequence)是指在一个给定序列找出一个最长子序列使得子序列的元素按照顺序递增。给定一个长度为n的序列A,最长上升子序列长度可以通过动态规划的方法求解。 假设dp[i]表示以第i个元素结尾的最长上升子序列长度,那么状态转移方程可以定义为: dp[i] = max(dp[j] + 1), 其0 <= j < i,A[j] < A[i] 首先,初始化dp数组为1,表示每个元素本身就构成一个长度为1的最长上升子序列。 然后,从左往右遍历数组A,对于每个元素A[i],遍历之前的所有元素A[j](j<i),如果A[j] < A[i],则更新dp[i]为dp[j]+1。 最后,返回dp数组的最大值即为最长上升子序列长度。 举个例子,给定序列A=[3, 10, 2, 1, 20],首先初始化dp数组为[1, 1, 1, 1, 1]。 遍历到元素10时,与3比较,满足条件A[j] < A[i],更新dp[1]为dp[0]+1,得到dp=[1, 2, 1, 1, 1]。 再遍历到元素2时,与3和10比较,均不满足条件,不更新dp数组,得到dp=[1, 2, 1, 1, 1]。 继续遍历到元素1时,与3、10和2比较,满足条件A[j] < A[i],更新dp[3]为dp[2]+1,得到dp=[1, 2, 1, 2, 1]。 最后遍历到元素20时,与3、10、2和1比较,均满足条件,更新dp[4]为dp[3]+1,得到dp=[1, 2, 1, 2, 3]。 返回dp数组的最大值3,即为最长上升子序列长度。 综上所述,利用动态规划可以求解最长上升子序列长度。 ### 回答3: 最长上升子序列(Longest Increasing Subsequence,LIS)是指在一个给定序列,找到一个最长子序列,使得这个子序列的元素按照严格递增的顺序排列。 设序列为a[1…n],定义dp[i]为以a[i]结尾的LIS的长度。那么转移方程可以表示为:dp[i] = max{dp[j] + 1 | 1 ≤ j < i, a[j] < a[i]}。 根据状态转移方程,我们需要遍历所有小于i的j,找到能够构成最长上升子序列的j,从而更新dp[i]。可以使用动态规划的思路,通过一个辅助数组dp来记录每个位置的最长上升子序列长度。 具体实现上,我们可以使用两个循环来遍历序列a,外层循环从1到n,内层循环从1到i。在内层循环,比较a[j]和a[i]的大小,若满足条件则更新dp[i]为较大值。 最后,我们只需要遍历dp数组的最大值,即为最长上升子序列长度。 例如,对于序列c = [1, 3, 5, 2, 4, 6, 7],通过使用动态规划的方法,我们可以得到dp = [1, 2, 3, 2, 3, 4, 5]。最长上升子序列长度为5。 最长上升子序列问题是一个经典的动态规划问题,它的时间复杂度为O(n^2)。同时,还存在更优化的解法,比如使用二分查找加速查找过程,将时间复杂度优化为O(nlogn)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值