首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

POJ 2250 Compromise:單詞級最長公共子序列 (LCS) 詳解

     編輯:C++ 入門

POJ 2250 Compromise:單詞級最長公共子序列 (LCS) 詳解

給定兩段文本(由小寫單詞組成,以 # 結束),求它們的最長公共子序列(LCS),即找出兩段文本中按順序出現的最長公共單詞序列。例如輸入兩段德文提案,輸出 die einkommen der abgeordneten muessen dringend verbessert werden。

問題建模

  • 將每段文本拆分為單詞數組 a[1..la], b[1..lb]。
  • 單詞長度 < 30,數量 < 100,標準 LCS DP 完全適用。
  • 需輸出具體序列,故需記錄路徑。

動態規劃與路徑記錄

d[i][j]:前 i 個單詞與前 j 個單詞的 LCS 長度。
pre[i][j]:記錄轉移來源(1=匹配,2=來自上方,3=來自左方)。

void lcs() {
    memset(d, 0, sizeof(d));
    memset(pre, 0, sizeof(pre));
    for (int i = 1; i < la; ++i)
        for (int j = 1; j < lb; ++j)
            if (!strcmp(a[i], b[j])) {
                d[i][j] = d[i-1][j-1] + 1;
                pre[i][j] = 1; // 匹配
            } else if (d[i-1][j] > d[i][j-1]) {
                d[i][j] = d[i-1][j];
                pre[i][j] = 2; // 來自上
            } else {
                d[i][j] = d[i][j-1];
                pre[i][j] = 3; // 來自左
            }
}

遞歸輸出路徑

void print(int i, int j) {
    if (pre[i][j] == 1) {
        print(i-1, j-1);
        if (flag) flag = 0; else printf(" ");
        printf("%s", a[i]);
    } else if (pre[i][j] == 2) print(i-1, j);
    else if (pre[i][j] == 3) print(i, j-1);
}

輸入處理關鍵

while (scanf("%s", a[1]) != EOF) {
    la = 1;
    while (scanf("%s", a[++la]), a[la][0] != '#'); // 讀第一段
    lb = 0;
    while (scanf("%s", b[++lb]), b[lb][0] != '#'); // 讀第二段
    lcs();
    print(la-1, lb-1);
    printf("\n");
}

注意事項

  • 單詞比較用 strcmp,區分大小寫(題目均為小寫)。
  • pre 數組僅需存方向,空間 O(N²) 完全可行(N≤100)。
  • 多組測試用例,直到 EOF。

此題是 LCS 經典應用的「單詞版」,掌握 dp + path 模板可解決所有需輸出具體序列的 LCS 變體。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved