長さがlen_x、len_yの二つの文字列の編集距離(レーベンシュタイン距離)を、二次元配列memo[len_x+1][len_y+1]に1度計算済みの編集距離を保存することで計算量をおさえつつ求めたいです。
同じ計算が必要になったときにこの保存してあった編集距離の値を参照する…というプログラムです。
最小で以下の再帰関数ldmemoの呼び出し回数をlen_x*len_yに抑えられることは分かっているのですが、実装の仕方が分かりません。
以下のメモ化の場合、例えば2文字と2文字の文字列の場合、再帰関数ldmemoの呼び出し回数は13回、3文字と3文字の場合28回、4文字と4文字の場合49回となります。これをそれぞれ22=4回、33=9回、4*4=16回…となるように実装したいです。
C
1#include <stdio.h> 2#include <stdlib.h> 3 4int countm=0; //再帰関数ldmemoの呼び出し回数 5 6int ldmemo(char *X,int m,char *Y,int n,int **memo); 7 8int main(void) 9{ 10 char *data_x; 11 char *data_y; 12 int len_x,len_y; 13 int **memo; 14 //memo:(len_x+1)*(len_y+1)要素数の二次元配列(標準入力からの読み取りは省略しています) 15 16 for(int i=0; i<len_x+1; ++i){ //memoを全て-1に初期化 17 for(int j=0; j<len_y+1, ++j){ 18 memo[i][j]=-1; 19 } 20 } 21 22 printf("%d ",ldmemo(data_x,len_x,data_y,len_y,memo)); //編集距離を出力 23 printf("%d\n",countm); //再帰関数の呼び出し回数を出力 24} 25 26int delta(char *X,int a,char *Y,int b) //X[a]とY[b]の合否によって0or1を返す 27{ 28 if(X[a]==Y[b]){ 29 return 0; 30 }else{ 31 return 1; 32 } 33} 34 35int ldmemo(char *X,int m,char *Y,int n,int **memo) //改良したい再帰関数 36{ 37 int edit=0; //返り値(編集距離) 38 39 if(memo[m][n]!=-1){ //求める編集距離が既にメモされている場合それを採用 40 edit_d=memo[m][n]; 41 }else if(m>=0 && n>=0){ //そうでない場合再帰によって編集距離edit_dを求めつつメモに記録 42 if(m==0 || n==0){ 43 edit_d=vmax_(m,n); //mとnの最大値を返す 44 memo[m][n]=edit_d; 45 }else{ 46 memo[m-1][n-1]=ldmemo(X,m-1,Y,n-1,memo); 47 ++countm; 48 49 memo[m-1][n]=ldmemo(X,m-1,Y,n,memo); 50 ++countm; 51 52 memo[m][n-1]=ldmemo(X,m,Y,n-1,memo); 53 ++countm; 54 55 edit_d=vmin3_(memo[m-1][n-1]+delta(X,m-1,Y,n-1),memo[m-1][n]+1,memo[m][n-1]+1); 56 //vmin3_:3つの整数の最小値を返す 57 } 58 } 59 memo[m][n]=edit_d; 60 return edit_d; 61}
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。