DPマッチングを用いた生物間の距離(人と猿は、人と魚より距離が近い)の算出

前提:

1.距離をアミノ酸の配列で計る

2.長い時間の間にアミノ酸が置き換わる(例えばcdefgからcdsfgに)距離2とする

3.長い時間の間に脱落が起こる(例えばcdefgcd*fgになる)距離1とする(*は脱落)

(言葉で言うと、置換より脱落が起こりやすい、ってこと)

課題:

2つのアミノ酸配列の距離を出すとき2つを並べて比較しますが、並べ方が色々考えられます。

例えば、abcc と aebcを並べて比較する時、

(1)          abcc    aebc   と並べるとbecbが置換されたことになり2か所置換なの距離2*2=4)

(2)              a*bcc   aebc* と並べることもできます(距離は脱落1+1で距離2)。

このように並べ方で距離が違ってきます。

長い間にどのような置換や脱落が起こったかは不明ですが、たぶん“距離が最小の変化が起きた”と考えるのが常識的です(この例でいえば(2))

 

そこで、今回の課題は、2つの生物間の距離最小になるような並べ替えを行い、その距離とします。

文字列が長くなるとこの“最小距離の文字配列”をみつけるのは容易ではありません。

そこで、DPを使って計算量を最小限にしようというわけです。

 

==

課題:

abcdef と abcddf との並べ方と最短距離を示しなさい。並べ方は複数あると思います。

また、

abcdef と abcef に関しても上と同様のことをしてみましょう。

==

プログラム:

#include <stdio.h>

#define das  1

#define dsb  1

#define I 5

#define J 6

int dab, i, j, sum0, sum1, sum2, D, IJ, Ix, Jx;

char A[I]={'o','c','d','e','f'};

char Ad[I+J];

char B[J]={'o','a','b','c','d','e'};

char Bd[I+J];

int g[I][J], del[I][J];

 

main(){

   g[0][0]=0;

   for( i=1; i<I; i++){

                  g[i][0]= g[i-1][0]+ das;

                  del[i][0]=-1;

   }

   for( j=1; j<J; j++){

                  g[0][j]= g[0][j-1]+ dsb;

                  del[0][j]=-3;

   }

   for(i=1; i<I; i++){

      for(j=1; j<J; j++){

         if(A[i]==B[j]) dab=0;

         else dab=2;

         sum0= g[i-1][j]+das;

         sum1= g[i-1][j-1]+ dab;

         sum2= g[i][j-1] +dsb;

         if(((sum0<sum1)&&(sum0<sum2))||((sum0==sum1)&&(sum0<sum2))||((sum0==sum2)&&(sum0<sum1))) {

            g[i][j]= sum0;

            del[i][j]= -1;

         }       

         if(((sum1<sum0)&&(sum1<sum2))||((sum1==sum0)&&(sum1<sum2))||((sum1==sum0)&&(sum1<sum2))) {

            g[i][j]= sum1;

            del[i][j]= -2;

         }        

         if(((sum2<sum0)&&(sum2<sum1))||((sum2==sum1)&&(sum2<sum0))||((sum2==sum0)&&(sum2<sum1))) {

            g[i][j]= sum2;

            del[i][j]= -3;

          }               

         if((sum1==sum0)&&(sum1==sum2)) {

            g[i][j]= sum1;

            del[i][j]= -2;        

         }                            

       }

    }

// 類似度表示

   printf("D=%d\n",g[I-1][J-1]);

// g[][]の表示

   for(i=0; i<I; i++){

      for(j=0;j<J;j++)  printf("%d,",g[i][j]);

      printf("\n");

   }

// deltaの表示  

   for(i=0; i<I; i++){

      for(j=0;j<J;j++)  printf("%d,",del[i][j]);

      printf("\n");

   }

// 最短経路決定

   for(i=0; i<I+J-1; i++){

      Ad[i]='o';

      Bd[i]='o';

   }

   Ix=I-1;

   Jx=J-1;     

      for(i=I+J-1; i>0 ;i--){

         if(del[Ix][Jx]==-2){

            Ad[i]= A[Ix];

            Bd[i]= B[Jx];

            Ix--;

            Jx--;

         }

         else if(del[Ix][Jx]==-3){

            Ad[i]= '*';

            Bd[i]= B[Jx];

            Jx--;

         }

         else if(del[Ix][Jx]==-1){

            Ad[i]= A[Ix];

            Bd[i]= '*';

            Ix--;

         }            

      }

// 最短経路表示

   for(i=0; i<I+J ;i++)

      if(Ad[i]!='o')  printf("%c",Ad[i]);

   printf("\n"); 

   for(i=0; i<I+J ;i++)

     if(Bd[i]!='o')   printf("%c",Bd[i]);

   printf("\n");   

}

最適(最短)経路は、g[][]の、お尻(I,J)からdel[][]を使って遡ります。