最長公共上公升子串行的DP解法及其優化

2021-07-22 09:52:30 字數 2374 閱讀 3736

最近學習了關於最長公共上公升子串行的dp做法,去網上查了一些資料。由於一方面感覺太凌亂,另一方面感覺icpc中懂得「為什麼」懂得「怎麼做」更加重要,於是自己就寫一些總結咯。

定義狀態

f[i][j]表示以a串的前i個整數與b串的前j個整數且以b[j]為結尾構成的lcis的長度。

狀態轉移方程:

①f[i][j] = f[i-1][j] (a[i] != b[j])

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

現在我們來說為什麼會是這樣的狀態轉移方程呢?

對於①,因為f[i][j]是以b[j]為結尾的lcis,如果f[i][j]>0那麼就說明a[1]..a[i]中必然有乙個整數a[k]等於b[j],因為a[k]!=a[i],那麼a[i]對f[i][j]沒有貢獻,於是我們不考慮它照樣能得出f[i][j]的最優值。所以在a[i]!=b[j]的情況下必然有f[i][j]=f[i-1][j]。

對於②,前提是a[i] == b[j],我們需要去找乙個最長的且能讓b[j]接在其末尾的lcis。之前最長的lcis在哪呢?首先我們要去找的f陣列的第一維必然是i-1。因為i已經拿去和b[j]配對去了,不能用了。並且也不能是i-2,因為i-1必然比i-2更優。第二維呢?那就需要列舉b[1]...b[j-1]了,因為你不知道這裡面哪個最長且哪個小於b[j]。這裡還有乙個問題,可不可能不配對呢?也就是在a[i]==b[j]的情況下,需不需要考慮f[i][j]=f[i-1][j]的決策呢?答案是不需要。因為如果b[j]不和a[i]配對,那就是和之前的a[1]...a[j-1]配對(假設f[i-1][j]>0,等於0不考慮),這樣必然沒有和a[i]配對優越。(為什麼必然呢?因為b[j]和a[i]配對之後的轉移是max(f[i-1][k])+1,而和之前的i`配對則是max(f[i`-1][k])+1。

樸素的lcis演算法實現

hdu 1423greatest common increasing subsequence為例。

預處理:

#include #include #include #include #include #include using namespace std;  

const int maxn = 1001;

int a[maxn], b[maxn];

int f[maxn][maxn];

int n, m;

void init()

核心**:

void dp()  

} }

int ans = 0;

for(int i = 1; i <= m; i++) ans = max(ans, f[n][i]);

printf("%d\n", ans);

}

以上的**的時間複雜度是o(n^3),那我們怎麼去優化呢?通過思考發現,第三層迴圈找最大值是否可以優化呢?我們能否直接把列舉最大的f[i-1][k]值直接算出來呢?假設存在這麼乙個序列a[i] == b[j],我們繼續看狀態轉移方程②,會發現b[j] > b[k],即當a[i] == b[j]時,可以

推出a[i] > b[k]

,那麼有了這個表示式我們可以做什麼呢?可以發現,我們可以維護乙個max值來儲存最大的f[i-1][k]值。即只要有a[i] > a[j]的地方,那麼我們就可以更新最大值,所以,當a[i] == b[j]的時候,f[i][j] = max+1,即可。

核心**:

void dp()  

} int ans = 0;

for(int i = 1; i <= m; i++) ans = max(ans, f[n][i]);

printf("%d\n", ans);

}

可以發現,其實上面的**有些地方與0/1揹包很相似,即每次用到的只是上一層迴圈用到的值,即f[i-1][j],那麼我們可以像優化0/1揹包問題利用滾動陣列來優化空間。

核心**:

void dp()  

} int ans = 0;

for(int j = 1; j <= m; j++) ans = max(ans, f[j]);

printf("%d\n", ans);

}

如果是求最長公共下降子串行呢?很明顯嘛,把狀態定義改動一下,即f[i][j]表示以a串的前i個整數與b串的前j個整數且以b[j]為結尾構成的lcds的長度,具體實現的時候只要把a[i] > b[j]改為a[i] < b[j]就可以啦。

擴充套件閱讀:

最長公共上公升子串行(dp)

題目 我是超連結 題解 講解 最開始的狀態 f i j 表示a陣列的第i項和b陣列的第j項結尾為b j 的最大長度,轉移 f i j f i 1 j a i b j max a i b j i kb k 這樣的效率是n 3的,列舉最大值的迴圈怎麼看都可以去掉,我們可以優化 觀察第二個式子,發現a i...

最長公共上公升子串行

題目描述 給定兩個整數序列,求它們的最長上公升公共子串行。輸入描述 輸入兩組資料,每組資料代表乙個整數序列,其輸入格式為 第一行輸入長度m 1 m 500 第二行輸入該序列的m個整數ai 231 ai 231 輸出描述 輸出共兩行。第一行輸出兩個序列的最長上公升公共子串行的長度l 第二行輸出該子串行...

最長公共上公升子串行

首先,在 a i b j 的時候有 dp i j dp i 1 j 為什麼呢?因為 dp i j 是以b j 為結尾的 lcia 如果dp i j 0 那麼就說明 a 1 a i 中必然有乙個字元 a k 等於b j 如果dp i j 等於0 呢?那賦值與否都沒有什麼影響了 因為 a k a i 那...