最长不下降子序列 DP

问题描述:

设有n个不相同整数组成的数列,记为:b(1),b(2),...,b(n)且b(i)<>b(j)(i<>j),若存在i1<i2<i3<...<ie且b(i1)<b(i2)<b(i3)<...<b(ie),则称为长度为e的不下降序列,程序要求:原数列出之后,求出最长不下降序列。

例如:13,7,9,16,38,24,37,18,44,19,21,22,63,15.其中13,16,18,19,21,22,63,就是一个长度为7的不下降序列,同时也有7,9,16,18,19,21,22,63组成的长度为8的不下降序列。

输入样例:

14

13 7 9 16 38 24 37 18 44 19 21 22 63 15

输出样例:

max=8

7 9 16 18 19 21 22 63

算法分析:

根据动态规划原理,由后往前进行搜索(当然从前往后也是一样)。

(1)对 b(n)来说,由于它是最后一个数,所以从b(n)开始查找时,只存在长度为一的不下降序列;

(2)若从b(n-1)开始查找,则存在下面两种可能性:

        若b(n-1)<b(n),则存在长度为二的不下降序列,b(n-1),b(n);

        若b(n-1)>b(n),则存在长度为一的不下降序列,b(n-1)或b(n).

(3)一般若从b(i)开始,此时最长不下降序列应该按下列方法求出:

在b(i+1),b(i+2),...,b(n)中,找出一个比b(i)大的且最长的不下降子序列,作为他的后继。

代码:

#include<bits/stdc++.h>
using namespace std;
int a[10010],b[10010],c[100010];
//a[i]记录原数值
//b[i]表示从i位置到n的最长不下降子序列
//c[i]表示从i位置开始最长不下降序列的下一个位置,若为0,则表示后面没有连接项
using namespace std;
int main()
{
    int n,i,j,max,k;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        cin>>a[i];
        b[i]=1;
        c[i]=0;
    }
    //输入原数列,并给bc赋初值
    for(i=n-1;i>=1;i--)//求最长不下降子序列
    {
        max=0;//i位置之前的最长不下降子序列
        k=0;
        for(j=i+1;j<=n;j++)
            if(a[i]<a[j]&&b[j]>max)
            {
                max=b[j];
                k=j;
            }
        if(max>0)
        {
            b[i]=max+1;
            c[i]=k;
        }
    }
    k=1;
    for(j=1;j<=n;j++)
        if(b[j]>b[k])
            k=j;//求最长不下降序列的起始位置
    cout<<"max="<<b[k]<<endl;
    while(k!=0)
    {
        cout<<a[k]<<' ';
        k=c[k];
    }
    cout<<endl;
    return 0;
}


猜你喜欢

转载自blog.csdn.net/sdau20171989/article/details/79317508