2021057 2006-08-14 17:39:09 Accepted 1027 C++ 00:00.01 428K St.Crux 两个字符串si和sk,每个字符匹配都有一个权值,要求他们的最大匹配权值。 很久以前在论坛上看过介绍,说和求最长子序列十分类似,因此很快就联想到了dp:) 事实上,这个题和LCS......确实很相似。同样是用一个二维数组来表示si的前i个数与sk的前k个数(字符)匹配的最大值,同样在f(n, m)处得解。不同的是LCs求的是最大长度,而这个求的是最大值。 所以用从下向上递推的思想分析。比如si=AT,sk=TA。当A和T匹配后,显然有一种情况:f(2, 2) = f(1,1) + a[2][2]; 那么移一位如何?即把si的T移动到TA的后面,使A和TA匹配,得f(2, 2) = f(1, 2) + T与-的匹配值。同理可得其他情况,在这些情况中取最大值即可。 #include <cstdio>#include <string> int a[5][5] = { {5, -1, -2, -1, -3}, {-1, 5, -2, -3, -4}, {-2, -3, 5, -2, -2}, {-1, -2, -2, 5, -1}, {-3, -4, -2, -1, 0} }, b[101][101], s0[101], s1[101];int n, m, t, ans; int mx(int a, int b, int c){ if(a >= b && a >= c) return a; if(b >= a && b >= c) return b; if(c >= a && c >= b) return c; else return -99999999;} void read(){ char tc; int k; scanf("%d ", &n); for(k = 0; k < n; k ++) { scanf("%c", &tc); if(tc == 'A') s0[k] = 0; if(tc == 'C') s0[k] = 1; if(tc == 'G') s0[k] = 2; if(tc == 'T') s0[k] = 3; } scanf("%d ", &m); for(k = 0; k < m; k ++) { scanf("%c", &tc); if(tc == 'A') s1[k] = 0; if(tc == 'C') s1[k] = 1; if(tc == 'G') s1[k] = 2; if(tc == 'T') s1[k] = 3; }} void init(){ memset(b, 0, sizeof(b)); int i, sum = 0; for(i = 1; i <= n; i ++) { sum += a[s0[i - 1]][4]; b[i][0] = sum; } sum = 0; for(i = 1; i <= m; i ++) { sum += a[s1[i - 1]][4]; b[0][i] = sum; } ans = -99999999;} void dp(){ int i, k; for(i = 1; i <= n; i ++) { for(k = 1; k <= m; k ++) { int ta = b[i - 1][k - 1] + a[s0[i - 1]][s1[k - 1]]; int tb = b[i][k - 1] + a[4][s1[k - 1]]; int tc = b[i - 1][k] + a[s0[i - 1]][4]; b[i][k] = mx(ta, tb, tc); } } ans = b[n][m];} void ps(){ int i; for(i = 0; i < n; i ++) { printf("%d ", s0[i]); } printf("\n"); for(i = 0; i < m; i ++) { printf("%d ", s1[i]); } printf("\n");} void pb(){ int i, k; for(i = 0; i <= n; i ++) { for(k = 0; k <= m; k ++) { printf("%d ", b[i][k]); } printf("\n"); } printf("\n");} int main(){ //freopen("in.txt", "r", stdin); scanf("%d", &t); int i; for(i = 0; i < t; i ++) { read(); init(); dp(); //pb(); printf("%d\n", ans); } return 0;}

评论