1. 程式人生 > 其它 >UVa 10723 - Cyborg Genes (LCS + dp)

UVa 10723 - Cyborg Genes (LCS + dp)

題目連結: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;
}