UVa 10723 - Cyborg Genes (LCS + dp)
阿新 • • 發佈:2021-07-30
題目連結:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1664
考察對於 \(LCS\) 的理解,最短字串肯定是兩串長度減去 \(LCS\) 的長度,而最短字串的數量,也可以用類似 \(LCS\) 的方法求出
設 \(f[i][j]\) 表示第一個字串前 \(i\) 個字元和第二個字串前 \(j\) 個字元所得到的 \(LCS\),\(g[i][j]\) 表示第一個字串前 \(i\) 個字元和第二個字串前 \(j\) 個字元所得到的最短字串的數量,考慮當前 \(LCS\)
如果 \(s[i] == t[j]\),說明 \(i,j\) 是 \(LCS\) 的最後一個字元,\(g[i][j] = g[i-1][j-1]\),在上一個最短字串後面新增一個字元,方案數不變
如果 \(s[i] != t[j]\),考慮 \(LCS\) 是從哪裡轉移過來的
如果 \(f[i-1][j] > f[i][j-1]\),則說明當前 \(LCS\) 最後一個字元之後只有一個不在 \(LCS\) 中的字元,因為字元間的相對位置不能改變,新新增的字元在最短字串中必須在 \(LCS\) 最後一個字元之後,所以 \(g[i][j] = g[i-1][j]\),表示放置完 \(LCS\)
而如果 \(f[i-1][j] = f[i][j-1]\),則說明當前 \(LCS\) 最後一個字元之後有不止一個不在 \(LCS\) 中的字元,這些字元的順序隨意,所以 \(g[i][j] = g[i-1][j] + g[i][j-1]\),表示這些字元所放的順序無所謂
最後注意輸入的字串可能含有空格,所以要使用 \(getline()\) 函式讀入
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 35; int T, n, m; int f[maxn][maxn], g[maxn][maxn]; ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; } int main(){ scanf("%d", &T); getchar(); int kase = 0; while(T--){ string a, b; getline(cin, a); getline(cin, b); n = a.length(), m = b.length(); a = " " + a; b = " " + b; memset(f, 0, sizeof(f)); memset(g, 0, sizeof(g)); g[0][0] = 1; for(int i = 1 ; i <= max(n, m) ; ++i) g[i][0] = g[0][i] = 1; for(int i = 1 ; i <= n ; ++i){ for(int j = 1 ; j <= m ; ++j){ if(a[i] == b[j]){ f[i][j] = max(f[i][j], f[i-1][j-1] + 1); g[i][j] = g[i-1][j-1]; } else{ if(f[i-1][j] > f[i][j-1]){ f[i][j] = max(f[i-1][j], f[i][j-1]); g[i][j] = g[i-1][j]; } else if(f[i-1][j] < f[i][j-1]){ f[i][j] = max(f[i-1][j], f[i][j-1]); g[i][j] = g[i][j-1]; } else{ f[i][j] = max(f[i-1][j], f[i][j-1]); g[i][j] = g[i-1][j] + g[i][j-1]; } } } } printf("Case #%d: %d %d\n", ++kase, n + m - f[n][m], g[n][m]); } return 0; }