这道通过率超过50%的题居然折腾了我一下午...仔细想一下首先就是题意没有理解清楚...开始自己推了一个DP...即:
首先判断s1与s2的长度...如果一样..则直接输出...如果strlen(s2)>strlen(s1)则把s1与s2换一下..
用a[ i ] [ j ] 数组来存状态..储存的状态是s1的前i个数中插了j个'-'..
状态转移则是 : a[ i ] [ j ] = max ( a[ i ] [ j - 1 ] + turn ( s1[ i ] , s2[ i - j ] ) , a [ i -1 ] [ j -1 ] + turn ( s1 [ i ] , ' - ' ) ) ( 1 <= i <= strlen(s1) , 0 < = j < = strlen(s1) - strlen(s2) )
交上去WA~~测了N个数据..终于发现BUG..没有考虑到:
2 AT
2 TA
这类情况...最优解应该是 -AT 与 TA- ... 但我开始的思路当两个串相等就直接求值~~~即AT直接与TA对应求值....出错的原因就是我完全没考虑到两个数组有可能都存在'-'的情况.
在最初的DP上加了很多条件和判断..希望能用最开始的DP调出来..但一直在WA....最后还是去看了Discuss了....这题正确的DP方程实在是美妙...自己的思维还是太死板了..根本没有想到那一步来..关于状态转移方程就ctrl + c , ctrl + v贴在下面...也提醒自己做DP的时候思维一定要放开...切中状态转移方程.. :
c[i][j]=max{c[i-1][j-1]+mat(a[i],b[j]),c[i][j-1]+mat('-',b[j]),c[i-1][j]+mat(a[i],'-')} (其中mat(x,y)表示字符x与y匹配的权值)
则有上述状态转移方程可得边界为:
c[0][0]=0
c[i][0]=c[i-1][0]+mat(a[i],'-')
c[0][j]=c[0][j-1]+mat('-',b[j])
DP搞了一个星期还是这个样子~~要继续努力了~~一些经典的状态转移方程也要整理下....
program :
#include<iostream> using namespace std; int t,l1,l2; char s1[301],s2[301]; int turn(char a,char b) { if (a=='A') { if (b=='A') return 5; if (b=='C') return -1; if (b=='G') return -2; if (b=='T') return -1; if (b=='-') return -3; } if (a=='C') { if (b=='A') return -1; if (b=='C') return 5; if (b=='G') return -3; if (b=='T') return -2; if (b=='-') return -4; } if (a=='G') { if (b=='A') return -2; if (b=='C') return -3; if (b=='G') return 5; if (b=='T') return -2; if (b=='-') return -2; } if (a=='T') { if (b=='A') return -1; if (b=='C') return -2; if (b=='G') return -2; if (b=='T') return 5; if (b=='-') return -1; } if (a=='-') { if (b=='A') return -3; if (b=='C') return -4; if (b=='G') return -2; if (b=='T') return -1; if (b=='-') return -1; } } int mmax(int a,int b,int c) { if ( a>b && a>c ) return a; if ( b>c ) return b; return c; } int DP() { int a[101][101],i,j,kans=0; memset(a,0,sizeof(a)); for (i=1;i<=l1;i++) a[i][0]=a[i-1][0]+turn(s1[i],'-'); for (i=1;i<=l2;i++) a[0][i]=a[0][i-1]+turn('-',s2[i]); for (i=1;i<=l1;i++) for (j=1;j<=l2;j++) a[i][j]=mmax(a[i-1][j-1]+turn(s1[i],s2[j]),a[i-1][j]+turn(s1[i],'-'),a[i][j-1]+turn('-',s2[j])); return a[l1][l2]; } int main() { scanf("%d",&t); while (t--) { for (int i=1;i<=300;i++) { s1[i]='-'; s2[i]='-'; } scanf("%d",&l1); for (int i=0;i<=l1;i++) scanf("%c",&s1[i]); scanf("%d",&l2); for (int i=0;i<=l2;i++) scanf("%c",&s2[i]); printf("%d\n",DP()); } return 0; }