动态规划刷题总结

本文介绍了动态规划的基本概念,通过最长上升序列(LIS)和最长不增序列的求解展示了动态规划的状态转移过程。同时,还探讨了洛谷导弹拦截问题,以及如何利用单调栈解决这类问题。此外,还涉及最长公共子序列(LCS)的暴力解法,并给出了一种优化思路。文章通过实例代码加深了对动态规划的理解,并提供了验证决策正确性的方法。
摘要由CSDN通过智能技术生成

动态规划基础问题

动态规划是优化的暴力,决策结果构成状态空间。动态规划的状态空间的遍历就是一张有向无环图,当前状态递推其后状态。当某一个状态确定后,不再受其后状态影响。
题目实现代码简单,难点在于状态表示决策的状态转移方程构造保证无后效性且合理,有时边界处理不当容易出错。在做题时可以输出状态空间验证决策是否正确。

最长上升序列LIS && 最长不增序列

洛谷导弹拦截
理解题目求解的是 最长不增序列&& 最长上升序列LIS

#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n,a[N];
int dpup[N],cntup,dplow[N],cntlow;
bool cmp(int x,int y){
    return x>y;
}
void solve(int a[]){
    cntlow=1;cntup=1;
    dplow[1]=a[1];
    dpup[1]=a[1];
    for(int i=2;i<=n;i++){
        //维护单调不增序列
        //小于等于末尾元素直接加入
        //不增即可以有相同元素出现,整体在减小,选择位置时不应该替代相同元素
        if(dplow[cntlow]>=a[i]) dplow[++cntlow]=a[i];
        else{
            int p=upper_bound(dplow+1,dplow+1+cntlow,a[i],cmp)-dplow;
            dplow[p]=a[i];
        }
        //维护单调递增序列
        //大于队尾元素直接插入
        //递增不允许相同元素出现,选择位置时可替代相同元素
        if(dpup[cntup]<a[i]) dpup[++cntup]=a[i];
        else{
            int p=lower_bound(dpup+1,dpup+1+cntup,a[i])-dpup;
            dpup[p]=a[i];
        }
        /*
        printf("不增\t");
        for(int i=1;i<=cntlow;i++) cout<<dplow[i]<<' ';
        cout<<endl;
        printf("递增\t");
        for(int i=1;i<=cntup;i++) cout<<dpup[i]<<' ';
        cout<<endl;
        */
    }
    cout<<cntlow<<endl<<cntup<<endl;
}
int main()
{
    while(scanf("%d",&a[++n])!=EOF);
    n--;
    solve(a);
}
/*
void test(){
    int b[]={0,1,2,3,3,5,7};
    cout<<upper_bound(b+1,b+6,2)-b<<endl;
    cout<<upper_bound(b+1,b+6,4)-b<<endl;
    cout<<upper_bound(b+1,b+6,5)-b<<endl;
    cout<<upper_bound(b+1,b+6,8)-b<<endl;
    //输出 3 5 6 6
    //返回大于const的第一个数的指针位置
    //最后大于最后一个仍然返回最后一个
}
/*
void test(){
    int b[]={0,1,2,3,3,5};
    cout<<lower_bound(b+1,b+5,3)-b<<endl;
    cout<<lower_bound(b+1,b+5,4)-b<<endl;
    cout<<lower_bound(b+1,b+5,5)-b<<endl;
    cout<<lower_bound(b+1,b+5,6)-b<<endl;
    //输出 3 5 5 5
    //返回大于等于const的第一个一个
}
*/

LCS

洛谷LCS模板

LCS 最大公共子序列,求解两个序列P1,P2 ,求它们的最长公共子序列。
暴力解法

#include<bits/stdc++.h>
using namespace std;
#define N 1010
int s1[N],s2[N],n;
int dp[N][N];
void LCS(int s1[],int s2[])
{
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(s1[i]==s2[j]){
                dp[i][j]=dp[i-1][j-1]+1;
            }else{
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
    }
    cout<<dp[n][n]<<endl;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>s1[i];
    for(int i=1;i<=n;i++) cin>>s2[i];
    LCS(s1,s2);
}

洛谷最大公共子序列题目,给的两个数列都是全排列,既保证了数据范围不会太大,又保证了子序列元素的唯一性,数列a中的元素必定会在数列b中出现。
如果将a数组映射到b数组,在b数组中仍能保持原顺序的部分就是最大公共子序列。

#include<bits/stdc++.h>
using namespace std;
#define N 101000
int s1[N],s2[N],n;
int dp[N],cnt,m[N];
void LIS(int s2[])
{
    //最长单调上升子序列
    dp[1]=s2[1];
    cnt=1;
    for(int i=2;i<=n;i++){
        if(dp[cnt]<s2[i]) dp[++cnt]=s2[i];
        else{
            //因为是排列所以low up无所谓
            int p=lower_bound(dp+1,dp+1+cnt,s2[i])-dp;
            dp[p]=s2[i];
        }
    }
    cout<<cnt<<endl;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s1[i];
        m[s1[i]]=i;
    }
    for(int i=1;i<=n;i++){
        cin>>s2[i];
        s2[i]=m[s2[i]];
    }
    LIS(s2);
}

未完。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值