• 最长递减子序列(转载)


    Q:例如:有一个序列,例如 9 8 2 1 7 5 3 4 3 2 1.
         求出最长的递减子序列。如本例的结果就是:9 8 7 5 4 3 2 1。

    分析:

            可采用动态规划的思想进行解答,时间复杂度为O(n^2).

           设原数组为a[1....n]。另设一数组d[1....n],其中d[i]表示从第i个元素开始(一定包含第i个元素),到整个数组末尾的子序列 a[i...n]中的最长递减子序列的长度。
           则本问题就是要在求出d[1]的同时,恢复出最优解。

       下面给出递推式:

    d[i]的值分两种情况:
    1、当i=n时,d[i]=1。即最后一个元素的序列的最大递减子序列中只有它自己。


    2、当i<n时,d[i]=max{d[k]| i<k<=n 且a[i]>a[k]} +1。解释意思为,包含第i个元素的序列a[i...n]的最大子序列依赖于i后面所有的序列中比a[i]小(满足递减
    特性),且最大的d[k](满足最 优特性)值再加1(加上a[i]元素)。在给d[i]赋值的时候只需记录p[i]=k,既可以作为parent属性恢复出解。

    具体实现的话,开两个数组d[n],p[n],外层循环从后往前选取i,内层循环从i往后寻找最优的k,双循环遍历即可求出所有的d[i]。然后 再进行一次O(n)操作,找出最大的d[max]。恢复解的话,可以从p[max]开始,依次恢复出各个解。

     #include <iostream.h>
     2 
     3 void longest_decrease_sub(int *a, int size)
     4 {
     5     
     6     int *d=new int[size]; //分配内存空间    
     7     int *p=new int[size];  //分配内存空间
     8     
     9     d[size-1]=1;
    10     
    11     for(int i=size-1;i>=0;i--)
    12     { 
    14         int max=0;   
    16         int index=0;
    17         
    18         for(int j=i;j<size;j++)
    19         {  
    21             if(a[i]>a[j] && max <d[j])
    22             { 
    24                 max=d[j];
    26                 index=j;        
    28             }
    30         }
    31         
    32         if(max==0)
    33         {
    34             
    35             d[i]=1;
    36             
    37             p[i]=-1;
    38             
    39         }
    40         else
    41         {
    42             
    43             d[i]=max+145             p[i]=index;          
    47         }        
    49     }     
    51     //寻找最大子序列的起始下标     
    53     int max=0;
    55     int max_index=0;   
    57     for( i=0;i<size;i++)
    58     {       
    60         if(d[i]>max)
    61         {
    62             
    63             max=d[i];
    64             
    65             max_index=i;
    66             
    67         }       
    69     }
    70     
    71     //从最大子序列的下标开始 输出子序列    
    72     cout<<"
    最长递减子序列的长度为:"<<d[max_index]<<",最长子序列为:"<<ends;
    73     
    74     for( i=max_index;i!=-1;i=p[i])
    75     {
    76         
    77         cout<<a[i]<<" "<<ends;
    78         
    79     }
    80     
    81     delete [] d;
    82     
    83     delete [] p;
    84     
    85 }
    86 
    87 void main()
    88 {
    89     int data[10]={1,2,5,4,3,2,7,8,9,0};
    90     longest_decrease_sub(data,10);
    91 }

    另外一个代码版本:

     1 #include <iostream>
     2 #include <vector>
     3 using namespace std;
     4 
     5 
     6 int main()
     7 {
     8     int n,m;
     9     cin>>n;
    10     while (n--) {
    11         cin>>m;
    12         vector<int>b(m);
    13         vector<int>f(m);
    14         for(int i=0;i<m;i++)
    15         {
    16             cin>>b[i];
    17             f[i]=1;
    18         }
    19         for(int i=1;i<m;i++)
    20             for(int j=0;j<i;j++)
    21             {
    22                 if(b[j]>=b[i]&&f[j]+1>f[i])
    23                     f[i]=f[j]+1;
    24             }
    25         int max=1;
    26         for(int i=0;i<m;i++)
    27         {
    28             if(f[i]>max)
    29                 max=f[i];
    30         }
    31         cout<<max<<endl;
    32     }
    33     return 0;
    34 }
  • 相关阅读:
    #18.2.27 codevs1098 均分纸牌
    18.2.26 codevs3143 二叉树的序遍历
    18.2.14 codevs1501 二叉树最大宽度和高度
    18.2.14 codevs1011 数的计算
    18.2.14 【水】codevs1475 m进制转十进制
    18.2.14 【水】codevs1474 十进制转m进制
    18.2.14 【水】codevs1430 素数判定
    18.2.13 codevs1212 最大公约数
    18.2.13 codevs1012 最大公约数和最小公倍数问题
    17.12.31 链表合并
  • 原文地址:https://www.cnblogs.com/SarahLiu/p/5859581.html
Copyright © 2020-2023  润新知