【算法基础(第五版)】例3.13 序列对准求最小值

来源:互联网 发布:淘宝秒杀需要刷新 编辑:程序博客网 时间:2024/05/18 01:36

算法基础(第五版)之序列对准
题目背景,给出两个同源DNA序列,不匹配罚一分,有缝隙(即一个字母对应一个短线)罚两分,例如:
对于序列AACAGTTACC和TAAGGTCA,
-AACAGTTACC和TAA-GGT–CA是一种对准方式,
AACAGTTACC和TA-AGGT-CA是另一种对准方式,第一种罚分数为1*2+2*4=10,第二种为1*3+2*2=7,第二种方式比第一种好,对准方式有很多种,如何找到最好的对准方式及求出最小罚分值。
思路:m[i][j]表示从s1的第i个位置和从s2的第j个位置开始对准最低罚分值,进而得到递推公式
若s1[i]==s2[j],
则m[i][j]=min(m[i+1][j]+2,m[i][j+1]+2,m[i+1][j+1])
若不等,
则m[i][j]=min(m[i+1][j]+2,m[i][j+1]+2,m[i+1][j+1]+1)
解释如下:对于s1的第i个字母和s2[j],可以s1[i]与s2[j]对准,可以S1[i]与‘-’对准,和s2[j]与‘-’对准。
从m[len1][len2]开始斜对角线递推至m[0][0]即为总最小惩罚值,路径根据打表之后从m[0][0]对比变化得知。代码如下:

#include<stdio.h>#include<string.h>#include<string>using namespace std;#define inf 0x3f3f3f3fint main(){    char s1[50];    char s2[50];    scanf("%s%s",s1,s2);    int m[55][55];    int strlen1=strlen(s1);    int strlen2=strlen(s2);    for(int i=0;i<55;i++)    {        for(int j=0;j<55;j++)        {            m[i][j]=inf;        }    }    //初始边界值,当s1字母对准至边界后,只能拿‘-’对准s2,惩罚值为后面字母的个数    for(int i=0;i<=strlen2;i++)    {        m[i][strlen1]=(strlen2-i)*2;    }    for(int i=0;i<=strlen1;i++)    {        m[strlen2][i]=(strlen1-i)*2;    }    //对角线法求dp表    for(int i=strlen1-2;i>=0;i--)    {        int x=strlen2-1;        int y=i+1;        while(y<strlen1)        {             //printf("%d %d\n",x,y);            m[x][y]=min(m[x+1][y],m[x][y+1])+2;            if(s1[y]==s2[x])            {                m[x][y]=min(m[x][y],m[x+1][y+1]);            }            else            {                m[x][y]=min(m[x][y],m[x+1][y+1]+1);            }            x--;            y++;        }    }    for(int i=strlen2-1;i>=0;i--)    {        int x=i;        int y=0;        while(x>=0)        {            m[x][y]=min(m[x+1][y],m[x][y+1])+2;            if(s1[y]==s2[x])            {                m[x][y]=min(m[x][y],m[x+1][y+1]);            }            else                m[x][y]=min(m[x][y],m[x+1][y+1]+1);            x--;            y++;        }    }    //输出最小值    printf("%d\n",m[0][0]);    //根据表格寻找对准路径    int xx=0,yy=0;    int ss1[55],ss2[55];    int cnt1=0,cnt2=0;    while(xx!=strlen2||yy!=strlen1)    {        if(m[xx][yy]==m[xx+1][yy]+2)        {            ss1[cnt1++]=yy;           // printf("s1:%d  ",yy);            xx++;        }        else if(m[xx][yy]==m[xx][yy+1]+2)        {            ss2[cnt2++]=xx;            //printf("s2:%d  ",xx);            yy++;        }        else        {            xx++;            yy++;        }    }     int ii=0;    for(int i=0;i<strlen1;i++)    {        if(ii<cnt1&&ss1[ii]==i)        {            printf("-");            ii++;        }        printf("%c",s1[i]);    }    printf("\n");    for(int i=0;i<strlen2;i++)    {        if(ii<cnt2&&ss2[ii]==i)        {            printf("-");            ii++;        }        printf("%c",s2[i]);    }    printf("\n"); }/*TAAGGTCAAACAGTTACCTAAGGTCA*/

感谢队友的强烈监督!

原创粉丝点击