LIS--最长升序子序列

子问题:
	第n个最长--》第i个最长,当i = n 成立
状态:
	maxSum[i] 表示 从第一个元素到第 i 个元素的最长子序列
边界:
	i == 1 时, maxSum[i] = 1
转移方程:
 	n=1时,maxSum[n] = 1;
 	选择时:标准a[i] 与 a[j] 大小
 		符合:a[i]>a[j] maxSum[i] =max(maxSum[i], maxSum[j]+1);
 		不符合:如果没有,则maxSum[i] = 1 	(第i个元素前边没有较小的!)

以上,初始化maxSum[i] = 1 (i = 1,2,…,n) 因为无论如何最长子序列不小于1

以int a[] = { 0,1,8,4,9,5,10 };为例
maxSum[i]的变化:...
maxSum[1] = 1
maxSum[2] = max(maxSum[2],maxSum[1]+1) = 2
maxSum[3] = max(maxSum[3],maxSum[1]+1) = 2  其中j = 2 时 没有操作 a[2]>a[3]  
maxSum[4] = 3
maxSum[5] = 3
maxSum[6] = 4

在 第 i 个元素之前,只要发现比 a[i] 小的 即 将该 j 位置 的 maxSum[j]+1 再与变化前的maxSum[i]比较选较大值;(毕竟不能 得出maxSum[i]的 maxSum(i -1) +1 就是最大值,所以每次都要比较max)
如下:

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
//递推:效率高
const int N = 10e6;
int a[N];
int maxSum[N];	
int main()
{
	//LIS
	int n;
	while (cin >> n)
	{
		int k;
		for (int i = 1; i <= n; ++i)
		{
			cin >> a[i];
			maxSum[i] = 1;		//i = 1时,即为1,初始化
		}
		//最长子序列个数,maxSum[i]表示在第i个数时的LIS解
		for (int i = 2; i <= n; ++i)
			for (int j = 1; j < i; ++j)	//把i看作n,对n内求解maxSum
			{
				if (a[i] > a[j])
					maxSum[i] = max(maxSum[i], maxSum[j] + 1);
			}
		cout << *max_element(maxSum + 1, maxSum + n +1) << '\n';
	}
	return 0;
}

注:*max_element(begin,end) 取一组数据之中的最大值

将这个题目变一下:

求最大上升子序列之和

思路还是一样,一个是最大和,一个是最长 ,都要求上升
因为由上升顺序在,所以按之前的思路:

子问题:
	从第1个到第n个最大和--》到第i个最大和,当i = n 成立
状态:
	maxSum[i] 表示 从第一个元素到第 i 个元素的最大子序列和
边界:
	i == 1 时, maxSum[i] = a[1]		//稍有变化
转移方程:
 	n=1时,maxSum[n] = a[1];
 	选择时:选择标准:a[i] 与 a[j] 大小
 		符合:a[i]>a[j] maxSum[i] =max(maxSum[i], maxSum[j]+1);
 		不符合:如果没有,则maxSum[i] = a[i] 	(第i个元素前边没有较小的!取其本身)

以上,初始化maxSum[i] = a[i] (i = 1,2,…,n) 因为无论如何最大上升子序列和不小于其本身
代码大致如下:(没多大变化)

#include <iostream>
#include <algorithm>
using namespace std;
//最大上升子序列和
int a[] = { 0,1,8,4,9,5,10 };
int maxSum[1 << 5];
int main()
{
	int n = 6;
	maxSum[1] = a[1];
	for (int i = 2; i <= 6; ++i)
	{
		maxSum[i] = a[i];
		//决定第i个元素 需要 前i-1个元素的上升序列==》比较范围 是前 i-1 个元素
		for (int j = 1; j < i; ++j)
		{
			if (a[i] > a[j])
				maxSum[i] = max(maxSum[j] + a[i], maxSum[i]);
		}
		cout << *max_element(maxSum + 1, maxSum + 7) << " \n"[i==6];
	}
	cout << *max_element(maxSum + 1, maxSum + 7);
	return 0;
}

Output:
9 9 18 18 28
28

Congratulations!可以goto下边儿这些个地方提升自己了
https://onlinejudge.org/
https://codeforces.com/problemsets/acmsguru
https://atcoder.jp/home
http://acm.hdu.edu.cn/listproblem.php?vol=1
https://leetcode-cn.com/problemset/algorithms/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值