動的プログラミング:最も長く一般的なサブシーケンスの問題
動的プログラミングの一般的な手順:
-
問題構造分析
2つのシーケンスX [n]、Y [m]が与えられた場合、X [n]、Y [m]の最長の共通サブシーケンスC [n] [m]の長さを見つけます。 -
再帰関係の確立
特定の例を使用して、シーケンスの最後にある文字を分析します。ケース1:X [n]、Y [m]の終了文字が異なる
ケース2:X [n]、Y [m]の終了文字は同じです。
最初にケース1:X [n]、Y [m]の終了文字が異なります。 1 2つの可能性があります:
(1)Y [m]の最後の文字、つまりC [7] [6-1] +0を
削除します。(2)X [m]の最後の文字、つまりC [7-1] [6を削除します。 ] +0:
したがって、再帰的な関係は次のようになります。C[i、j] = max {C [i -1、j]、C [i、j-1]}ケース2を
見てみましょう:X [n]、Y [m]終了文字は同じです。ケース2には3つの可能性があります。(1)X [n]、Y [m]の終了文字が同時に選択されて非表示になり、次のステップはC [7-1,6-1] +1ですが2つです。これらは必ずしも最長のサブシーケンスに表示されるとは限らないため、(2)と(3)の2つの可能性があります。(2)Y [m]の最後の文字、つまりC [7] [6-1] +0を削除します。(3)X [m]の最後の文字、つまりC [7-1] [6] +0を削除します。これらの3つの可能性を解決する必要はありません。分析では、C [i-1、j-1] +1>が示されています。 = max {C [i、j -1]、C [i-1、j]であるため、最終的な再帰関係は次のようになります。C[i、j] = C [i -1、j-1] +1
-
ボトムアップ計算
(1)初期化:C [i、0] = C [0、j] = 0;シーケンスの長さが0の場合、最長の共通サブシーケンスの長さは0です。
(2)再帰式:
-
最適なソリューション追跡
追跡配列rec [n]を作成して、サブ問題の原因を記録します
アルゴリズム図
コード
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
string X,Y;
int C[1001][1001];//记录公共子序列长度
int main(){
cin >> X >> Y;
int n = X.length(), m = Y.length();
//初始化
for(int i=0; i<n; i++)
C[i][0] = 0;
for(int j=0; j<n; j++)
C[0][j] = 0;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(X[i]==Y[j])
C[i][j] = C[i-1][j-1]+1;
else
C[i][j] = max(C[i][j-1],C[i-1][j]);
}
}
cout << C[n][m] << endl;//输出最长公共子序列长度
return 0;
}