编辑距离问题(2)——DNA序列对齐

编辑距离问题是对其两个DNA序列问题的一般化,有许多通过对齐的方法来度量两个DNA序列的相似度。其中一种对齐方式是在两个序列x和y之间插入空格(包括两端),使得序列结果x'和y'有相同的长度而且不在同一位置均为空格(也就是说,没有位置j使得x'[j]和y'[j]均为空格)。然后给每个位置一个“分数”。位置j以如下方式得到一个分数:

+1 ,如果x'[j]=y'[j]而且都不是空格;

-1   ,如果x'[j]!=y'[j]而且都不是空格;

-2 ,如果x'[j]或者y'[j]是空格;

以上摘自《算法导论》p219,现给出两个DNA序列,求出两个DNA序列的对其方式使其分数最大。

这个转换我最初是没有想到的,但是看了别人的说明百度文库,最初看完以为上面说的有点不大对,但是仔细分析了一下,觉的真是巧妙啊:

cost(copy)=-1                复制操作,相当于对齐后x'[i]=y'[i],分数+1

cost(replace)=+1          替换操作,相当于对齐后x'[j]!=y[j],分数-1(都不为空格)

cost(delete)=+2             删除操作,相当与在DNA序列x中插入一个空格后使之与y对齐,分数+2

cost(insert)=+2              插入操作,相当与在DNA序列y中插入一个空格后使之与x对齐,分数+2

这样就将如何获得一个具有最大分数的DNA对齐方式的问题,转换为具有最短编辑距离的问题了。

#include <iostream>
#include <vector>
#include <string>
using namespace std;

const int costCopy=-1;
const int costReplace=1;
const int costDelete=2;
const int costInsert=2;
enum {cop=1,replace,del,insert};

void trackBack(vector < vector<int> > operMatrix,const string &s1,
     const string &s2){
     int len1=s1.size();
     int len2=s2.size();
     string seq1,seq2;
     int i=len1;
     int j=len2;
     while(i>0&&j>0){
         switch(operMatrix[i][j]){
           case 1://copy
           {
             seq1.insert(seq1.begin(),s1[i-1]);
             seq2.insert(seq2.begin(),s2[j-1]);
             i--;j--;
             break;
           }
           case 2://replace
           {
             seq1.insert(seq1.begin(),s1[i-1]);
             seq2.insert(seq2.begin(),s2[j-1]);
             i--;j--;
             break;
           }
           case 3://delete
           {
             seq1.insert(seq1.begin(),s1[i-1]);
             seq2.insert(seq2.begin(),' ');
             i--;
             break;
           }
           case 4://insert
           {
             seq1.insert(seq1.begin(),' ');
             seq2.insert(seq2.begin(),s2[j-1]);
             j--;
             break;
           }      
         }
     }
     if(i==0){
       for(;j>0;j--){ 
         seq1.insert(seq1.begin(),' ');
         seq2.insert(seq2.begin(),s2[j-1]);
       }
     }
     else{
       for(;i>0;i--){
         seq1.insert(seq1.begin(),s1[i-1]);
         seq2.insert(seq2.begin(),' '); 
       }
     }
     cout<<seq1.c_str()<<endl;
     cout<<seq2.c_str()<<endl;
}

int levenshteinDistance(const string &s1,const string &s2){
  int len1=s1.size();
  int len2=s2.size();
  if(!len1) return len2;
  if(!len2) return len1;
  
  vector <vector <int> > dp(len1+1,vector <int>(len2+1,0));
  //record the action
  vector <vector <int> > oper(len1+1,vector <int>(len2+1,0));

  //initialize dp
  for(int i=1;i<len1+1;i++){
    dp[i][0]=dp[i-1][0]+costDelete;
    oper[i][0]=del;
  }
  for(int j=1;j<len2+1;j++){
    dp[0][j]=dp[0][j-1]+costInsert;
    oper[0][j]=insert;
  }

  //dp
  for(int i=1;i<=len1;i++){
    for(int j=1;j<=len2;j++){
      int minDis=0;
      if(s1[i-1]==s2[j-1]){
        minDis=dp[i-1][j-1]+costCopy;
        oper[i][j]=cop;
      }
      else{
        minDis=dp[i-1][j-1]+costReplace;
        oper[i][j]=replace;
      }
      int tempDis=dp[i-1][j]+costDelete;
      if(minDis>tempDis){
        minDis=tempDis;
        oper[i][j]=del;
      }
      tempDis=dp[i][j-1]+costInsert;
      if(minDis>tempDis){
        minDis=tempDis;
        oper[i][j]=insert;
      }
      dp[i][j]=minDis;
    }
  }
  cout<<"***************************"<<endl;
  for(int i=0;i<=len1;i++){
    for(int j=0;j<=len2;j++){
      cout<<dp[i][j]<<" ";
    }
    cout<<endl;
  }
  cout<<"**************************"<<endl;
  cout<<"***************************"<<endl;
  for(int i=0;i<=len1;i++){
    for(int j=0;j<=len2;j++){
      cout<<oper[i][j]<<" ";
    }
    cout<<endl;
  }
  cout<<"**************************"<<endl;

  trackBack(oper,s1,s2);
  return dp[len1][len2];
}



int main(){
  string s1("GATCGGCAT");
  string s2("CAATGTGAATC");
  cout<<"编辑距离:"<<levenshteinDistance(s1,s2)<<endl;
  return 0;
}

运行效果如下:


你可能感兴趣的:(算法导论)