这道题困扰了我好久。我最开始是想不到为什么他们这样写可以直接确定加入空格之后的连两个字符串的长度是相同的。我现在明白了,原来我不明白事情的时候都是搞两个例子模拟一下,有一段时间没有做了,渐渐忘却了。用例子模拟是一个很好的帮助理解的方式。下面来说说思路:
一般的动态规划无非是某一个东西要或者不要的状态。这里是一样。我们假设现在第一个字符串的第i个字符和和第二个字符串的第j个字符对应结果最大,那么dp[i][j]由前面推出来有三种情况:i-1个和j-1个对应,i-1个后面插入一个空格,j-1后面插入一个空格。还有一点就是那么最后两者的长度是不是一样的???答案是是的,如果不理解的同学自己找一个字符串模拟一下就好了,所以状态转移方程:f[i][j]=max(f[i][j-1]+val('-',s2[j]),f[i-1][j]+val(s1[i],'-'));
f[i][j]=max(f[i-1][j-1]+val(s1[i],s2[j]),f[i][j]);
下面是AC的代码:
#include<iostream>
using namespace std;
#include<cstdio>
#include<algorithm>
#include<cstring>
char s1[105],s2[105];
int f[105][105];
int num[6][6]=
{
0,0,0,0,0,0,
0,5,-1,-2,-1,-3,
0,-1,5,-3,-2,-4,
0,-2,-3,5,-2,-2,
0,-1,-2,-2,5,-1,
0,-3,-4,-2,-1,-1000000,
};
int get1(char a)
{
if(a=='A')return 1;
else if(a=='C')return 2;
else if(a=='G')return 3;
else if(a=='T')return 4;
else return 5;
}
int val(char a,char b)
{
return num[get1(a)][get1(b)];
}
int main()
{
int n;
int i,j,k;
cin>>n;
while(n--)
{
int n1,n2;
memset(f,0,sizeof(f));
scanf("%d%s",&n1,s1+1);
scanf("%d%s",&n2,s2+1);
for(i=1;i<=n1;i++)
f[i][0]=f[i-1][0]+val(s1[i],'-');
for(i=1;i<=n2;i++)
f[0][i]=f[0][i-1]+val('-',s2[i]);
for(i=1;i<=n1;i++)
for(j=1;j<=n2;j++)
{
f[i][j]=max(f[i][j-1]+val('-',s2[j]),f[i-1][j]+val(s1[i],'-'));
f[i][j]=max(f[i-1][j-1]+val(s1[i],s2[j]),f[i][j]);
}
cout<<f[n1][n2]<<endl;
}
return 0;
}