例1:给你两个字符串,找出最长子序列的长度。
对于字符串t, 字符串s,给定特定的i, j代表t,s的位置,只存在三种情况:
1. i == 0 || j==0, M[i][j] = 0;
2. t[i] == s[j], M[i][j] = min(M[j-1][j-1] + 1, M[i-1][j], M[i][j-1]);//.....不知道怎么解释。。。。
3. t[i] != s[j] , M[i][j] = min(M[i-1][j], M[i][j-1]);//。。。。。
经典dp题
代码:
#include <iostream> #include <cstring> using namespace std; string s, t; int M[1000][1000]; int hasgo[1000][1000]; int dp(int a, int b) { if(hasgo[a][b] > 0) return M[a][b]; if(!a || !b) return 0; if(s[a-1] == t[b-1]) { M[a][b] = max(dp(a-1, b-1) + 1, M[a][b]); } M[a][b] = max(M[a][b], dp(a, b - 1)); M[a][b] = max(M[a][b], dp(a - 1, b)); hasgo[a][b] = 1; return M[a][b]; } int main() { while(cin >> s >> t) { memset(M, 0, sizeof(M)); memset(hasgo, 0, sizeof(hasgo)); cout << dp(s.size(), t.size()) << endl; } return 0; }
升级版最长公共子序列
例2:给你n条字符串,找出最长公共子序列的长度。
如果按照上面的思路,如果是三条,弄个三维数组就好了,几条字符串就弄几维数组,但这题维数没法确定,,,就涉及到dp中一个常用的技巧,,子问题编码,对于A(a[1], a[2], a[3] .... a[n])代表
各个串中的位置,给这个数组独一无二的编码: index = a[1] + a[2] * len[1] + a[3] * len[2] + ... + a[n] * len[n-1], 这样一个一维数组M[index]就可以表示每种状态的最长子串了。
(len 是各个串的长度)
1. 有一个为0, M[index] = 0;
2. 都相等的时候, M[index] = min(M[index], M[index'] + 1), index' = a[i'] = a[i] - 1;for(int i = 1; i <= n; i++),A[i]--; M[index] = M[index'];
3.for(int i = 1; i <= n; i++),A[i]--; M[index] = M[index'];(当然,是在len1 * len2 * len 3 *...在可接受的范围内。。。)
代码
#include <iostream> #include <cstring> using namespace std; ///多个字符串找最大公共子串,对于每一个串确定的位置(d1, d2, d3,...,dn),可能存在三种情况,当前位置的字母都是相同的, int *len, *A, *M, *xishu;///字符串长度, 系数, 最长公共子序列,系数单位 char str[105][105]; int n; int hasgo[30005]; int solve(int index) { if(hasgo[index] > 0) return M[index]; for(int i = 0; i < n; i++) if(!A[i]){hasgo[index] = 1; return 0;} int ok = 1; for(int i = 0; i < n - 1; i++) if(str[i][A[i]] != str[i+1][A[i+1]]) ok = 0; if(ok) { int ii = index; for(int i = 0; i < n; i++) { A[i]--; ii -= xishu[i]; } M[index] = max(solve(ii) + 1, M[index]); for(int i = 0; i < n; i++) A[i]++; } int ii = index; for(int i = 0; i < n; i++) { ii -= xishu[i]; A[i]--; M[index] = max(solve(ii), M[index]); A[i]++; ii += xishu[i]; } hasgo[index] = 1; return M[index]; } int main() { int t; cin >> t; while(t--) { cin >> n; len = new int[n]; A = new int[n]; M = new int[30005](); xishu = new int[n]; int ii = 0; // memset(M, 0, sizeof(M)*30005); memset(hasgo, 0, sizeof(hasgo)); for(int i = 0; i < n; i++) { cin >> str[i]; } for(int i = 0; i < n; i++) { len[i] = strlen(str[i]); A[i] = len[i]; xishu[i] = (!i ? 1 : xishu[i-1]*len[i-1]); ii += A[i] * xishu[i]; } cout << solve(ii) << endl; delete []M; delete []A; delete []xishu; delete []len; } }