dp基礎 關於LIS LCS LCIS 的一些總結

2021-08-19 02:56:56 字數 2809 閱讀 7622

lis:(最長遞增子串行)

dp思路:dp[i] 為0到第i項的最長遞增子串行長度。

dp[i] = max(dp[j])+1    a[j] < a[i]

dp[0] = a[0];

for( int i = 1 ; i < n ; i++ )

}}

二分優化:

if( a[i] > dp[tot1] )else

注意:dp[i]儲存的是長度為i時最長遞增子串行的最小結尾。陣列整個儲存的並不是最長遞增子串行。

如果想要輸出最長遞增子串行,可以使用第一種未使用二分優化的寫法,加乙個記錄前面節點的陣列。

下面是乙個示例程式:(輸出需要回溯)

#include using namespace std;

const int ax = 1e5+6;

int dp[ax];

int a[ax];

int pre[ax];

void print( int x )

cout << a[x] << endl;

}int main()

dp[0] = 1;

int tot = 0;

int index ;

memset( pre , -1 , sizeof(pre) ) ;

for( int i = 1 ; i < n ; i++ )

}} if( tot < dp[i] )

} cout << tot << endl;

print(index);

return 0 ;

}

lcs:最長公共子串行

dp[i][j]表示a字串的前i項與b字串的前j項匹配所得到的最長公共子串行長度。

dp[i][j] = dp[i-1][j-1] + 1   ;  a[i] == b[j]

dp[i][j] = max(dp[i-1][j] , dp[i][j-1])   ; a[i] != b[j]

#include using namespace std;

const int ax = 1e3+6;

int dp[ax][ax];

char res[ax];

int main()else dp[i][j] = max( dp[i-1][j] , dp[i][j-1] );

} }cout << dp[la][lb] << endl;

int i = la , j = lb;

int tot = 0 ;

while( i >= 1 && j >= 1 )elseelse

} }for( int k = tot - 1 ; k >= 0 ; k-- )cout << endl;

return 0 ;

}

滾動陣列優化空間:

for( int i = 1 ; i <= la ; i ++ )else dp[i%2][j] = max( dp[(i-1)%2][j] , dp[i%2][j-1] );

} }

lcis : 最長公共上公升子串行

dp[i][j] 表示以 a 序列的前 i 項, b 序列的前 j 項,並且以 b[j] 為結尾的 lcis 的長度。

如果a[i] != b[j]  那麼 只能a[i]之前的數 與 b[j]配對 。

如果a[i] == b[j] ,那麼dp[i][j]就是前面最長序列的長度+1

因此可得轉移方程:

dp[i][j] = dp[i-1][j] ;   a[i] != b[j]

dp[i][j] = max( dp[i-1][k] ) + 1    a[i] == b[j]    (1 <= k <= j - 1 && b[j] > b[k])

這個演算法最關鍵的是,如果按照乙個合理的遞推順序,max(f[i-1][k])的值我們可以在之前訪問f[i][k]的時候通過維護更新乙個max變數得到。怎麼得到呢?首先遞推的順序必須是狀態的第一維在外層迴圈,第二維在內層迴圈。也就是算好了f[1][len(b)]再去算f[2][1]。 如果按照這個遞推順序我們可以在每次外層迴圈的開始加上令乙個max變數為0,然後開始內層迴圈。當a[i]>b[j]的時候令max=f[i-1][j]。如果迴圈到了a[i]==b[j]的時候,則令f[i][j]=max+1。

for( int i = 1 ; i <= n ; i++ )

if( a[i-1] == b[j-1] )

}} int res = 0;

for( int i = 1 ; i <= m ; i++ )

那麼如何輸出lcis序列呢?其實跟輸出最長遞增子串行類似:

首先增設乙個pre的二維陣列,(最長遞增子串行設定乙個一維即可),記錄到當前狀態是接在誰後面得來的。

每次得到a,b相等時,記錄前一狀態。

for( int i = 1 ; i <= n ; i++ )

}if( a[i-1] == b[j-1] )

} }

輸出:先找到最後末尾匹配的點p,然後得出整個序列。

int p;

for( int i = 1 ; i <= m ; i++ )

} for( int i = n - 1 , j = p , k = res ; k > 0 ; i-- )

} cout << res << endl;

for( int i = 0 ; i < res ; i++ )

刷題向》DP》關於基礎DP easy

openjudge 8464 這道題其實很簡單,算是dp的基礎題,比較適合開拓dp思維。題目比較有欺騙性,其實稍微想想就可以解決,因為題意說第一次賣出後才能 所以我們可以考慮列舉斷點,所以題目一下變得簡單,我們線性掃兩遍,算最大值就好了。具體為 由於不能同時進行兩次交易,所以列舉斷點,一遍掃做1到n...

DP基礎(線性DP)總結

前言 雖然確實有點基礎.但凡事得腳踏實地地做,基礎不牢,地動山搖,嗯!dp方程 dp i max 複雜度 o n 2 法一 資料結構無腦暴力優化 以a i 為陣列下標,從1到a i 訪問最大值,再加一,進行更新 法二 設h k 表示dp值為k的最長上公升子串行的最小值 有點貪心在裡面 顯然h k h...

dp基礎小結

kuangbin帶你飛系列,基礎dp 總共20多道題,就不一一說了 說一下學會的關鍵的思路 第1點 有的時候某一狀態的值的得出,可能會要我們列舉已經計算過的值,一一比較取最值,但如果真的去列舉的話就會超時,這時我們可以把狀態的含義設為前i項的最值,計算的時候只需要多比較一項,即和前一項比較一下就可以...