LCS问题,自己做的WA了。
从网上摘了一个差不多的AC掉了。
解题思路:
网上一份解题报告:写的很详细,就此摘来:
http://nash250.blog.hexun.com/9794371_d.html
和《算法导论》中动态规划章节的LCS(Longest common subsequence 最长公共子序列)所用例子基本是一样的,都是测两串基因的相似程度,不同之处在于《导论》用LCS表示两基因的相似程度,LCS越长,相似度越大。本题中用下面的核苷相近程度取值表表示两基因相似程度,各相应核苷对匹配值之和越高,相似程度自然越大。
首先回想LCS的解法,
设两基因串为an,bm
a[i],b[j]分别表示a串的第i个核苷
b串的第j个核苷
ax,by为an,bm的子串;
c[x][y]表示子串ax,by间最长子序列的长度
则c[n][m]表示串an,bm间最长子序列的长度
则有如下的状态转移方程:
c[i][j]=c[i-1][j-1]+1 if i,j>0 a[i]=b[j]
c[i][j]=max(c[i][j-1],c[i-1][j]) if i,j>0 a[i]≠[j]
再思考该动规方程的边界条件:
for i=0 to n do c[i, 0] ← 0
for j=0 to n do c[0, j] ← 0
即每个子序列与长度为0的串的最长子序列的长度为0
此即为LCS的解法
针对本题,对LCS的状态方程稍作修改,
设两基因串为an,bm
a[i],b[j]分别表示a串的第i个核苷
b串的第j个核苷
ax,by为an,bm的子串;
c[x][y]表示子串ax,by间最大相似程度值
则c[n][m]表示串an,bm间最大相似程度值
value(x,y)表示核苷x核苷y的相似程度值
'-'表示核苷为空
则有如下的状态转移方程:
c[i][j]=max(c[i-1][j-1]+value(a[i],b[j]),c[i][j-1]+value('-',b[j]),c[i-1][j]+value(a[i],'-'))
if i,j>0 a[i]≠[j]
再思考该动规方程的边界条件:
for i=0 to n do c[i][0] ← 0
for j=0 to n do c[0][j] ← 0
即每个子序列与空串之间的相似程度值的和为0
至此本题的思路已经清晰
提交情况:
Wa两次:没分析清楚临界情况。
注意:
考虑清楚临界情况。
源程序:
#include <iostream>
using namespace std;
long a[110],b[110],v[110][110];
long r[][5]={0,-3,-4,-2,-1,-3,5,-1,-2,-1,-4,-1,5,-3,-2,-2,-2,-3,5,-2,-1,-1,-2,-2,5};
long change(char c)
{
switch (c)
{
case'A': return 1;
case'C': return 2;
case'G': return 3;
case'T': return 4;
}
}
int main()
{
long caseNum,aLen,bLen,i,j,tmp,all,aOnly,bOnly;
char c;
cin>>caseNum;
while(caseNum--)
{
cin>>aLen;
for(i=1;i<=aLen;i++)
{
cin>>c;
a[i]=change(c);
}
cin>>bLen;
for(i=1;i<=bLen;i++)
{
cin>>c;
b[i]=change(c);
}
v[0][0]=0;
for(i=1;i<=aLen;i++) v[i][0]=r[a[i]][0]+v[i-1][0];
for(i=1;i<=bLen;i++) v[0][i]=r[0][b[i]]+v[0][i-1];
//临界情况是当前这个点和 "-" 得到的值,
//与前面累加得到的,而不仅仅是当前点得到的值
for(i=1;i<=aLen;i++)
for(j=1;j<=bLen;j++)
{
all=v[i-1][j-1]+r[a[i]][b[j]];
aOnly=v[i-1][j]+r[a[i]][0];
bOnly=v[i][j-1]+r[0][b[j]];
tmp=aOnly>bOnly?aOnly:bOnly;
v[i][j]=all>tmp?all:tmp;
}
cout<<v[aLen][bLen]<<endl;
}
return 0;
}