动态规划:最长递增子序列

最长递增子序列

给出序列:
1 2 3 4 2 5 3 4
a[1]=1,a[2]=2,…,a[7]=3,a[8]=4
求其最长的递增子序列,以上最长递增子序列为:1 2 3 4 5
问题细分
初始化条件F[1]:1,序列只有1个长度即为1
F[2]:a[2]与下标小于2的比较,即a[1]比较,a[2]>a[1],因此更新F[2] = F[1]+1 =2,取F[1~2]最大值2
F[3]:a[3]与下标小于3的比较,即a[1],a[2]比较,a[3]>a[2]>a[1],因此更新F[3] = F[2]+1 =3,取F[1~3]最大值3
F[4]:a[4]与下标小于4的比较,即a[1],a[2],a[3]比较,a[4]>a[3]>a[2]>a[1],因此更新F[4] = F[3]+1 =4,取F[1~4]最大值4
F[5]:a[5]与下标小于5的比较,即a[1],a[2],a[3],a[4]比较,a[5]>a[1],因此更新F[5] = F[1]+1 =2 ,取F[1~4]最大值4,F[5]更新
F[6]:a[6]与下标小于6的比较,即a[1],…a[5]比较,a[6]>a[4],因此更新F[6] = F[4]+1 =5 ,取F[1~6]最大值5
F[7]:a[7]与下标小于7的比较,即a[1],…a[6]比较,a[7]>a[2],因此更新F[7] = F[2]+1 =3 ,取F[1~7]最大值5,F[7]更新
F[8]:a[8]与下标小于8的比较,即a[1],…a[7]比较,a[8]>a[3],因此更新F[8] = F[3]+1 =4 ,取F[1~8]最大值5,F[8]更新

F[i]:a[i]与下标小于i的比较,注意是所有,如 7 8 1 2 3 8,第一次8>7进行更新,可是8同样大于1 2 3,因此需要遍历完(也可以这样理解,F[i]表示以a[i]结尾!!!的最长递增子序列),然后取最大值作为F[i],最后再从F[1~i]取最大值,若发现F[i]不是最大值,则更新F[i]的数值为所求得的最大值,所以说:要求两次最大值 m_m,因此再求一个序列的最大子序列长度时,可以不必要每个F[i]都求得,在保证最长子序列不变的情况下,通过最后一次遍历,找到最大值即为所求,于是有方法二,下面给出上方所列方法一的各个F情况:
方法一:

12342534
F[1]F[2]F[3]F[4]F[5]F[6]F[7]F[8]
12344555

这里比较方式可能和课本有些不同,因为每次求得F[i],并比较了F[1~i]并取最大值。

方法二:有些地方在求一个序列最大的递增子序列长度时也可以每次获得F[i]后不进行取最大值,而是求得所有F[i],后再求F[i~n]中最大值作为,序列最大递增子序列的长度,这种做法,可行,但是F[i]并不是代表a[1],…a[i]的最长递增子序列长度,而是表示以a[i]结尾的最长递增子序列长度,这里列出这种方式求得的F[i]
方法二:

12342534
F[1]F[2]F[3]F[4]F[5]F[6]F[7]F[8]
12342534

可以看到F[5]为2,这是因为添加了a[5]=2进序列,a[5]>a[1],只能说添加了a[5]的作用只是延长a[1]序列,故F[5]=F[1]+1=2,但 1 2 3 4 2 最长的递增子序列依旧是 1 2 3 4 ,所以a[5]的添加对其无影响,因此在求最后总的最长递增子序列时,可以只进行一次求最大值操作,还需要注意的是,要是a[i]不大于它之前所有的a,如a[5] =0,此时F[5],人为给其设定为1
给出最长递增子序列递推公式:
F[1] = 1;
F[I] = max{1 , F[j] + 1 | a[j] < a[i] && j < i };

题目

Code(c++)

#include<iostream>
#include<iomanip>
#define N 25

using namespace std;
int missile[N+1];
int dp[N];
int max(int a, int b) { return a>b ? a : b; }
void lis(int k) {
	for (int x = 1; x <= k; x++) {
		int tmax = 1;
		for (int i = 1; i < x; i++) {
			if (missile[i] >= missile[x]) {
				tmax = max(tmax, dp[i] + 1);
			}
		}
		dp[x] = tmax;
		//cout << setw(3)<< dp[x] << " ";
	}
	
}
int main() {
	int k;
	cin >> k;
	for (int i = 1; i < k; i++) {
		cin >> missile[i];
		
	}
	lis(k);
	int ans = 1;
	for (int i = 1; i <= k; i++) {
		ans = max(ans, dp[i]);
	}
	cout << ans << endl;
	return 0;
}

/*
6
1 4 3 2 6 5

8
300 207 155 300 299 170 158 65

*/
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值