对线性DP的简单总结(19.3.30~19.4.5)

一.线性DP的概念

线性dp是很基础的一种动态规划,经典题和他的变种有很多(我还是比较菜,先理解好简单的吧…)比如两个串的LCS,LIS,最大子序列和等等,线性dp是用来解决一些 线性区间上的最优化问题 .

二.线性DP举例

(1)最长公共子序列
描述
A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, …, xm > another sequence Z = < z1, z2, …, zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, …, ik > of indices of X such that for all j = 1,2,…,k, xij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.
输入
The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.
输出
For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.
大意
给出两个字符串,求两个字符串的最长公共字串。
分析
这种题还是用图来表示比较清晰明了(上图!我还是不太会调大小…各位先凑活看吧)
在这里插入图片描述
我们就可以推出这么一个式子:
如果a[i]=b[j];
F[i][j]=F[i-1][j-1]+1;
如果a[i]!=b[j];
F[i][j]=max(F[i-1][j],F[i][j-1]);
那我们话不多说,(结合各路大神思路)直接上代码:

#include<stdio.h>
#include<string.h>
int f[1001][1001];
int main()
{
    char a[1001],b[1001];
    int i,j,len1,len2;
    while(~scanf("%s %s",a,b))
    {
        len1=strlen(a);
        len2=strlen(b);
        for(i=0;i<=len1;i++)
        {
            f[i][0]=0;
        }
        for(i=0;i<=len2;i++)
        {
            f[0][i]=0;
        }
        for(i=1;i<=len1;i++)
        {
            for(j=1;j<=len2;j++)
            {
                if(a[i-1]==b[j-1])
                {
                    f[i][j]=f[i-1][j-1]+1;
                }
                else
                {
                    f[i][j]=f[i-1][j]>f[i][j-1]?f[i-1][j]:f[i][j-1];
                }
            }
        }
        printf("%d\n",f[len1][len2]);
    }
    system("pause");
    return 0;
}

(2)最长上升子序列
描述
A numeric sequence of ai is ordered if a1 < a2 < … < aN. Let the subsequence of the given numeric sequence (a1, a2, …, aN) be any sequence (ai1, ai2, …, aiK), where 1 <= i1 < i2 < … < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).
Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
输入
The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000
输出
Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.
分析
我们来简单描述一下步骤
ep:
a[i]:用此来存储前第i个数的最长子序列
{1}--------------------------a[1]=1表示最长子序列是{1}
{1,6}-----------------------a[2]=a[1]+1=2表示前两个数里最长上升子序列为{1,6}
{1,6,4}---------------------a[3]=a[1]+1=2由于4<6,所以是a[1]+1。{1,6}{1,4}
{1,6,4,2}------------------a[4]=a[1]+1=2同理上一步,仍是{1,6}{1,4}
{1,6,4,2,3}----------------a[5]=a[4]+1=3这里3>2,为{1,2,3}
{1,6,4,2,3,9}-------------a[6]=a[5]+1=4按这个推理,这里为{1,2,3,9}
{1,6,4,2,3,9,8}-----------a[7]=4这里可以看出,这里为{1,2,3,9}{1,2,3,8}
理解了上面的过程,就可以上代码了

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int n;
    while(cin>>n)
    {
       int a[1001]={0},m=-1,d[1001]={0};// d用于保存第i个数字时的最长子序列     m用于保存d[i]数组中的最长子序列的个数
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        d[1]=1; 
        if(n<2)
            cout<<d[1]<<endl;//数组长度为1的时候,最长子序列也是1
        else
        {
            for(int i=2;i<=n;i++)
            {
                for(int j=1;j<i;j++)
                {
                    if(a[j]<a[i])   // 如果比第j个数比第i个数小,递增
                        d[i] = max(d[i],d[j]); //第i个数之前的最长上升子序列
                }
                d[i]=d[i]+1;// 在第i个之前加上自身 等于第i个数的最长上升子序列
                m = max(d[i],m);
            }
        }
        system("pause");
        cout<<m<<endl;
    }
    return 0;
}

线性dp基本上是从这两类出发,然后再进一步延申,背包问题好像也可用线性dp做,但我感觉和贪心的思路相差不大,也就不做详解了。

三.总结

这周又深入学习了动态规划——线性DP,然而自己还是菜,这里只能简单说一下对线性DP的基本例子,对一些变种例题,我怕是还不能叙述清楚明白,我还需要不断做题理解,这里只是我粗略的理解,如有不对之处,还烦请各路大神指出!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值