最长上升子序列(dp基础)

我来水文章了,它甚至毫无解释~

原问题:

题目来自代码源 

解释(不是):

经典思路:从后向前推导,找出转移方程

集合:以 a[i] 结尾的所有单调上升子序列

目标:数量最大

转移方程:if(a[j] < a[i])  dp[i] = max(dp[i], dp[j] + 1)  (i > j)

AC代码:

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int a[1010], dp[1010], n;
int main(void)
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d", &a[i]);
	} 
	//初始化 
	for(int i = 1; i <= n; i++)
		dp[i] = 1;
	//找出以a[i]结尾的最长上升子序列dp[i]
	for(int i = 1; i <= n; i++){
		for(int j = 1; j < i; j++){
			if(a[j] < a[i])
				dp[i] = max(dp[i], dp[j] + 1);
		}
	}
	//遍历输出最长上升子序列
	int res = 0;
	for(int i = 1; i <= n; i++)
		res = max(res, dp[i]);
	cout <<res <<endl;
	return 0;
}

扩展一:求最大上升子序列和:

最大上升子序列和,那什么会不一样呢?

1.初始值,总不能还是 1 吧,肯定变 a[ i ] 了呀

2.转移方程

dp[ i ] = max( dp[ i ],  dp[ j ] + a[ i ]);  

代码: 

#include <iostream>
using namespace std;
int a[10010], dp[10010], n;
int main(void)
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    //找出以a[i]结尾的最大子序列和dp[i]
    for(int i = 1; i <= n; i++){
        dp[i] = a[i];
        for(int j = 1; j < i; j++){
            if(a[j] < a[i])
                dp[i] = max(dp[i], dp[j] + a[i]);
        }
    }
    //遍历查找最大子序列和
    int res = 0;
    for(int i = 1; i <= n; i++)
        res = max(res, dp[i]);
    
    cout <<res <<endl;
    return 0;
}

扩展二:求最长的先上升后下降子序列

 什么意思呢?就是字面意思

 解决方法显而易见, 直接沿红线剪开,拆分成两个不同方向的最长上升子序列问题,搞定

代码:

#include <iostream>
using namespace std;
int a[10010], n;
int dp1[10010], dp2[10010];
int main(void)
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    //初始化
    for(int i = 1; i <= n; i++)
        dp1[i] = dp2[i] = 1;
    //找出以a[i]结尾的最长上升子序列dp1[i]
    for(int i = 1; i <= n; i++){
        for(int j = 1; j < i; j++){
            if(a[j] < a[i])
                dp1[i] = max(dp1[i], dp1[j] + 1);
        }
    }
    //找出以a[i]结尾的最长下降子序列dp2[i]
    for(int i = n; i >= 1; i--){
        for(int j = n; j > i; j--){
            if(a[j] < a[i])
                dp2[i] = max(dp2[i], dp2[j] + 1);
        }
    }
    //遍历找出最大值
    int res = 0;
    for(int i = 1; i <= n; i++){
        res = max(res, dp1[i] + dp2[i] - 1);
    }
    cout <<res <<endl;
    return 0;
}

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UmVfX1BvaW50

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值