【动态规划初级】longest increasing subsequence

目录
  • 最长非降子序列的长度LIS
  • 最长子序列拓展
  • 最长公子序列LCS
1.最长非降子序列的长度
一个序列有N个数:A[1],A[2],A[3]……A[N],求最长非降子序列的长度。
最重要的是要找出所谓的“状态”,本题目中是d[i],初始化最长长度为自己本身即一个单位长度。
看是否要加入第i个元素,如果第i个元素a[i]比当前序列的最后一个元素a[j]大的话,那么加入,同时d[i]=d[j]+1;体会d[j]+1>d[i] ,比如,对于序列【5,3,4,8,6,7】当i=3,即a[i]=8的时候,j=0,8比5大,d[3]=d[0]+1=2;j=1,8比3大,但是d[1]+1=2不比d[3]大就不能加一;j=2,8>4,d[2]+1=3>d[3],所以d[3]=d[2]+1;len保存的是前i个元素中的最大非降子序列的长度。

怎么能好好体会其中的思想而不去死记硬背,勉强自己去接受这一想法呢!

状态转移方程

d[i]=max{1,d[j]+1},其中j<i,a[j]<=a[i]

#include <iostream>
using namespace std;

int lis(int a[],int n){
    int d[n];
    int len=1;
    for(int i=0;i<n;i++){
        d[i]=1;
        for(int j=0;j<i;j++){
            if(a[j]<=a[i]&&d[j]+1>d[i]){
                d[i]=d[j]+1;
            }
            if(d[i]>len)len=d[i];

        }
    }
    return len;
}
int main()
{
    int a[]={5,3,4,8,6,7};
    cout<<lis(a,6)<<endl;
    return 0;
}

2.LIS拓展
 Problem Statement for ZigZag

Problem Statement

    

A sequence of numbers is called a zig-zag sequence if the differences between successive numbers strictly alternate between positive and negative. The first difference (if one exists) may be either positive or negative. A sequence with fewer than two elements is trivially a zig-zag sequence.

For example, 1,7,4,9,2,5 is a zig-zag sequence because the differences (6,-3,5,-7,3) are alternately positive and negative. In contrast, 1,4,7,2,5 and 1,7,4,5,5 are not zig-zag sequences, the first because its first two differences are positive and the second because its last difference is zero.

Given a sequence of integers, sequence, return the length of the longest subsequence of sequence that is a zig-zag sequence. A subsequence is obtained by deleting some number of elements (possibly zero) from the original sequence, leaving the remaining elements in their original order.

 

Definition

    
Class:ZigZag
Method:longestZigZag
Parameters:int[]
Returns:int
Method signature:int longestZigZag(int[] sequence)
(be sure your method is public)
    
 

Constraints

-sequence contains between 1 and 50 elements, inclusive.
-Each element of sequence is between 1 and 1000, inclusive.
 

Examples

0)
    
{ 1, 7, 4, 9, 2, 5 }
Returns: 6
The entire sequence is a zig-zag sequence.
1)
    
{ 1, 17, 5, 10, 13, 15, 10, 5, 16, 8 }
Returns: 7
There are several subsequences that achieve this length. One is 1,17,10,13,10,16,8.
2)
    
{ 44 }
Returns: 1
3)
    
{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }
Returns: 2
4)
    
{ 70, 55, 13, 2, 99, 2, 80, 80, 80, 80, 100, 19, 7, 5, 5, 5, 1000, 32, 32 }
Returns: 8
5)
    
{ 374, 40, 854, 203, 203, 156, 362, 279, 812, 955,
600, 947, 978, 46, 100, 953, 670, 862, 568, 188,
67, 669, 810, 704, 52, 861, 49, 640, 370, 908,
477, 245, 413, 109, 659, 401, 483, 308, 609, 120,
249, 22, 176, 279, 23, 22, 617, 462, 459, 244 }
Returns: 36

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2010, TopCoder, Inc. All rights reserved.



本题拓展为相邻的不是递增或者递减而是 相邻元素之差的正负号交互。
 
#include<stdio.h>
#include<iostream>
using namespace std;

#define LEN 100

int a[LEN];
int d[LEN];
int lis(int n){
    if(n==1){return 0;}
    int len=0;
    for(int i=0;i<n;i++){
        d[i]=1;
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<i;j++){
            if(j>0&&i>0&&(a[j-1]-a[i-1])*(a[j]-a[i])<0 && d[j]+1 >d[i])
                d[i]=d[j]+1;
            if(len<d[i])len=d[i];
        }
    }
    return len;
}
int main(){
    int n;
    freopen("in.txt","r",stdin);
   while(cin>>n){

    for(int i=0;i<n;i++)
        cin>>a[i];
        cout<<lis(n)+1<<endl;
   }
return 0;
}

3.最长公共子序列
   最长公共子序列是指,一个序列S如果分别为两个或者多个序列的子序列,且是所有符合此条件中最长的,则S为已知序列的最长公共子序列。(注意不一定连续)
例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。
我们是自底向上的进行递推计算,那么在计算dp[i][j]之前,dp[i][j-1],dp[i-1][j],dp[i][j]均已计算出来,此时我们根据a[i]==a[j]和a[i]!=a[j],就可以计算dp[i][j]
状态转移方程
回溯输出最长子序列过程。
#include<iostream>
#include<stdio.h>
#include<memory.h>
using namespace std;
#define LEN 100
char a[LEN];
char b[LEN];
int dp[LEN][LEN];
int vis[LEN][LEN];
int lcs(int m,int n){
    for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            dp[i][j]=0;
            vis[i][j]=0;
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            if(a[i]==b[j]){
                dp[i][j]=dp[i-1][j-1]+1;
                vis[i][j]=0;
            }
            else if(dp[i][j-1]>=dp[i-1][j]){
                dp[i][j]=dp[i][j-1];
                vis[i][j]=2;
            }else{
                dp[i][j]=dp[i-1][j];
                vis[i][j]=1;
            }

        }
    }
    return dp[m-1][n-1];
}
void printLCS(int i,int j){
    if(i==0|j==0)return ;
    if(vis[i][j]==0){
        printLCS(i-1,j-1);
        cout<<a[i];
    }
    if(vis[i][j]==1){
        printLCS(i-1,j);
    }
    if(vis[i][j]==2){
        printLCS(i,j-1);
    }

}

int main()
{
    freopen("in.txt","r",stdin);
    int m,n;

    while(cin>>m>>n)
    {

        for(int i=0; i<m; i++)
        {
            cin>>a[i];
        }
        for(int j=0; j<n; j++)
        {
            cin>>b[j];
        }
        cout<<lcs(m,n)<<endl;
        printLCS(m,n);
    }
}

测试用例
7 5
A B C B D A B 
B D C B A 

结果
3
CBA










posted @ 2014-05-20 09:02  空暖  阅读(506)  评论(0)    收藏  举报