POJ 1080 Human Gene Functions(动态规划)

题目来源:POJ 1080 Human Gene Functions

http://acm.pku.edu.cn/JudgeOnline/problem?id=1080

 

 

解法类型:动态规划

 

 

解题思路:

         网上一份解题报告:写的很详细,就此摘来:

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;

}

转载于:https://www.cnblogs.com/goodness/archive/2010/03/05/1678894.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值