1. 程式人生 > >動態規劃解最長子序列問題

動態規劃解最長子序列問題

動態規劃法

經常會遇到複雜問題不能簡單地分解成幾個子問題,而會分解出一系列的子問題。簡單地採用把大問題分解成子問題,並綜合子問題的解匯出大問題的解的方法,問題求解耗時會按問題規模呈冪級數增加。

為了節約重複求相同子問題的時間,引入一個數組,不管它們是否對最終解有用,把所有子問題的解存於該陣列中,這就是動態規劃法所採用的基本方法。

【問題】 求兩字元序列的最長公共字元子序列

問題描述:字元序列的子序列是指從給定字元序列中隨意地(不一定連續)去掉若干個字元(可能一個也不去掉)後所形成的字元序列。令給定的字元序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X

的一個嚴格遞增下標序列<i0,i1,…,ik-1>,使得對所有的j=0,1,…,k-1,有xij=yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一個子序列。

考慮最長公共子序列問題如何分解成子問題,設A=“a0,a1,…,am-1”,B=“b0,b1,…,bm-1”,並Z=“z0,z1,…,zk-1”為它們的最長公共子序列。不難證明有以下性質:

(1) 如果am-1=bn-1,則zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一個最長公共子序列;

(2) 如果am-1!=bn-1,則若zk-1!=am-1,蘊涵“z0

,z1,…,zk-1”是“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一個最長公共子序列;

(3) 如果am-1!=bn-1,則若zk-1!=bn-1,蘊涵“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一個最長公共子序列。

這樣,在找A和B的公共子序列時,如有am-1=bn-1,則進一步解決一個子問題,找“a0,a1,…,am-2”和“b0,b1,…,bm-2”的一個最長公共子序列;如果am-1!=bn-1,則要解決兩個子問題,找出“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一個最長公共子序列和找出“a0,a1,…,am-1”和“b0,b1

,…,bn-2”的一個最長公共子序列,再取兩者中較長者作為A和B的最長公共子序列。

求解:

引進一個二維陣列c[][],用c[i][j]記錄X[i]與Y[j] 的LCS 的長度,b[i][j]記錄c[i][j]是通過哪一個子問題的值求得的,以決定搜尋的方向。
我們是自底向上進行遞推計算,那麼在計算c[i,j]之前,c[i-1][j-1],c[i-1][j]與c[i][j-1]均已計算出來。此時我們根據X[i] = Y[j]還是X[i] != Y[j],就可以計算出c[i][j]。

問題的遞迴式寫成:

recursive formula

回溯輸出最長公共子序列過程:

flow

演算法分析:
由於每次呼叫至少向上或向左(或向上向左同時)移動一步,故最多呼叫(m + n)次就會遇到i = 0或j = 0的情況,此時開始返回。返回時與遞迴呼叫時方向相反,步數相同,故演算法時間複雜度為Θ(m + n)。

程式碼:

#include <stdio.h>
#include 
<string.h>
#define MAXLEN 100

void LCSLength(char*x, char*y, int m, int n, int c[][MAXLEN], int b[][MAXLEN])
{
    
int i, j;
    
    
for(i =0; i <= m; i++)
        c[i][
0=0;
    
for(j =1; j <= n; j++)
        c[
0][j] =0;
    
for(i =1; i<= m; i++)
    
{
        
for(j =1; j <= n; j++)
        
{
            
if(x[i-1== y[j-1])
            
{
                c[i][j] 
= c[i-1][j-1+1;
                b[i][j] 
=0;
            }

            
elseif(c[i-1][j] >= c[i][j-1])
            
{
                c[i][j] 
= c[i-1][j];
                b[i][j] 
=1;
            }

            
else
            
{
                c[i][j] 
= c[i][j-1];
                b[i][j] 
=-1;
            }

        }

    }

}


void PrintLCS(int b[][MAXLEN], char*x, int i, int j)
{
    
if(i ==0|| j ==0)
        
return;
    
if(b[i][j] ==0)
    
{
        PrintLCS(b, x, i
-1, j-1);
        printf(
"%c ", x[i-1]);
    }

    
elseif(b[i][j] ==1)
        PrintLCS(b, x, i
-1, j);
    
else
        PrintLCS(b, x, i, j
-1);
}


int main(int argc, char**argv)
{
    
char x[MAXLEN] ={"ABCBDAB"};
    
char y[MAXLEN] ={"BDCABA"};
    
int b[MAXLEN][MAXLEN];
    
int c[MAXLEN][MAXLEN];
    
int m, n;
    
    m 
= strlen(x);
    n 
= strlen(y);
    
    LCSLength(x, y, m, n, c, b);
    PrintLCS(b, x, m, n);
    
    
return0;
}

相關推薦

動態規劃長子序列問題

動態規劃法 經常會遇到複雜問題不能簡單地分解成幾個子問題,而會分解出一系列的子問題。簡單地採用把大問題分解成子問題,並綜合子問題的解匯出大問題的解的方法,問題求解耗時會按問題規模呈冪級數增加。 為了節約重複求相同子問題的時間,引入一個數組,不管它們是否對最終解有用,把

HDU acm 1003 Max Sum || 動態規劃大子序列和詳

line namespace num more sequence mem ould 動態規劃 ger Max Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot

31.動態規劃-乘積大子序列-Leetcode 152(python)

題目描述 給定一個整數陣列 nums ,找出一個序列中乘積最大的連續子序列(該序列至少包含一個數)。 示例 示例 1: 輸入: [2,3,-2,4] 輸出: 6 解釋: 子陣列 [2,3] 有最大乘積 6。 示例 2: 輸入: [

動態規劃——乘積大子序列

題目連結:http://www.lintcode.com/zh-cn/problem/maximum-product-subarray/ 參考資料:http://blog.csdn.net/wzy_1988/article/details/9319897        

nyoj 17-單調遞增長子序列(動態規劃,演算法)

clear ron queue orange 處理 描述 clas mes math 17-單調遞增最長子序列 內存限制:64MB 時間限制:3000ms Special Jud

動態規劃——長子序列

動態規劃法 經常會遇到複雜問題不能簡單地分解成幾個子問題,而會分解出一系列的子問題。簡單地採用把大問題分解成子問題,並綜合子問題的解匯出大問題的解的方法,問題求解耗時會按問題規模呈冪級數增加。 為了節約重複求相同子問題的時間,引入一個表(陣列)記錄所有已解決的子問題的答案,不管它們是否對最終

單調遞增長子序列動態規劃

單調遞增最長子序列 題目描述: 求一個字串的最長遞增子序列的長度 如:dabdbf最長遞增子序列就是abdf,長度為4 輸入描述: 第一行一個整數0<n<20,表示有n個字串要處理 隨後的n行,每行有一個字串,該字

nyist oj 17 單調遞增長子序列 (動態規劃經典題)

單調遞增最長子序列 時間限制:3000 ms  |  記憶體限制:65535 KB 難度:4 描述求一個字串的最長遞增子序列的長度 如:dabdbf最長遞增子序列就是abdf,長度為4

動態規劃:ZOJ1074-大和子矩陣 DP(長子序列的升級版)

To the Max Time Limit:1 Second     Memory Limit:32768 KB Problem Given a two-dimensional a

10.19—動態規劃 //長公共子序列//防衛導彈//田忌賽馬//計算矩陣連乘積//長子序列的長度

1.最長公共子序列 描述:一個給定序列的子序列是在該序列中刪去若干元素後得到的序列。確切地說,若給定序列X=<x1, x2,…, xm>,則另一序列Z=<z1, z2,…, zk>是X的子序列是指存在一個嚴格遞增的下標序列 <i1, i2,…,

動態規劃長公共子序列問題

clas == 搜索 ios for 參考 pan 公式 是否 題目描述: 給定兩個字符串s1s2……sn和t1t2……tn。求出這兩個字符串最長的公共子序列的長度。字符串s1s2……sn的子序列指可以表示為si1si2……sim(i1<i2<……<im)

動態規劃長遞增子序列(LIS)

lib sca while -c -o 組成 describe log ret 在一個已知的序列{ a1,a2,……am}中,取出若幹數組成新的序列{ ai1, ai2,…… aim},其中下標 i1,i2, ……im保持遞增,即新數列中的各個數之間依舊保持原

動態規劃長公共子序列(LCS)

int tdi -s can 數組下標 include har 遞推 最長公共子序列 在字符串S中按照其先後順序依次取出若幹個字符,並講它們排列成一個新的字符串,這個字符串就被稱為原字符串的子串 有兩個字符串S1和S2,求一個最長公共子串

動態規劃長公共子序列

圖片 輔助 length ret %s csp TP 子序列 輸出 原理請參考《算法導論》 定義常量 enum {upper_left, up, left}; #define LENGTHA (sizeof(A)/sizeof(A[0])) #define LENGTHB

動態規劃長遞增子序列的長度

main cpp 動態規劃 using string sub 給定 數組最長遞增子序列 ios 問題 給定一個長度為N的數組,找出一個最長的單調自增子序列(不一定連續,但是順序不能亂)。例如:給定一個長度為6的數組A{5, 6, 7, 1, 2, 8},則其最長的單調遞增子

動態規劃之----長公共子序列

什麽是 資料 lcs 由於 main detail span www. 遞歸 一,問題描述 給定兩個字符串,求解這兩個字符串的最長公共子序列(Longest Common Sequence)。比如字符串1:BDCABA;字符串2:ABCBDAB 則這兩個字符串的最長

【NOJ1041】【DP_動態規劃長公共子序列

1041.最長公共子序列 時限:1000ms 記憶體限制:200000K  總時限:3000ms 描述 一個給定序列的子序列是在該序列中刪去若干元素後得到的序列。確切地說,若給定序列X=<x1, x2,…, xm>,則另一序列Z=<z1, z2,

HDU 1160 FatMouse's Speed(動態規劃 LIS長不下降子序列

題目連結: #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <cstdlib> #include <map>

NOIP2004合唱隊列(提高組T3)————單調佇列,動態規劃長上升序列長下降序列

題解:本題主要考查單調佇列,動態規劃(最長上升序列,最長下降序列)。這個序列是一箇中間高,兩頭底的序列,先解決從T1到Ti這一段單調遞增的序列,再解決Ti到TK這一段單調遞減的序列(注意數值的更新)。 程式碼如下: #include<iostream> #include<

動態規劃實現長公共子序列

1 public class Test2 { 2 3 static int[][] result; 4 static String str1 = "ABCBDAB"; 5 static String str2 = "BDCABA"; 6 static cha