Sequence of Balls

ciao a tutti, sto provando a risolvere Sequence of Balls utilizzando l’algoritmo di Levenshtein ma non riesco a superare i 58 punti, potreste indicarmi dove sbaglio?

#include < iostream>
using namespace std;

int minimo(int x, int y, int z){
return min(min(x,y),z);
}

int mat[4005][4005];

int main(){
int costoInserimento,costoCancellazione,costoRimpiazzo,costoScambio,i,j,N,M;
string NA;
string NB;
freopen(“input.txt”,“r”,stdin);
freopen(“output.txt”,“w”,stdout);
cin>>costoInserimento>>costoCancellazione>>costoRimpiazzo>>costoScambio;
cin>>NA>>NB;
N=NA.size();
M=NB.size();
NA=" “+NA;
NB=” "+NB;
for(i=0;i<=N;i++){
mat[i][0]=costoCancellazionei;
}
for(j=0;j<=M;j++){
mat[0][j]=costoInserimento
j;
}
int cost = 0;
for(i=1;i<=N;i++){
for(j=1;j<=M;j++){
if(NB[j]==NA[i]){
cost=0;
}else{
cost=costoRimpiazzo;
}
mat[i][j] = minimo(mat[i-1][j]+costoCancellazione, mat[i][j-1]+costoInserimento,mat[i-1][j-1]+cost);
if(i>1 && j>1 && (NA[i-1]==NB[j] && NA[i]==NB[j-1])){
mat[i][j] =min(mat[i][j],mat[i-2][j-2]+costoScambio);
}
}
}
cout<<mat[N][M];
}

Ciao, la Levenshtein distance non basta per risolvere questo problema, per risolverlo devi invece usare la Damerau–Levenshtein distance.

Ciao, stando alle specifiche 2*CostoSwap>=CostoInserimento+CostoCancellazione questa configurazione non dovrebbe verificarsi … o sbaglio?
Ho utilizzato il link che mi hai girato tu per determinare l’algoritmo, dovrei utilizzare la variante Distance with adjacent transpositions?

Hai ragione, mi ero perso questa condizione. Ecco un esempio che dovrebbe essere corretto in cui il tuo programma sbaglia:

1 1 1 1
abc
ca

Si, attento che il codice nell’esempio prevede che tutti i costi siano pari a 1.

Grazie Borto, ci sono quasi(95%), ho riadattato una versione dell’algoritmo per java ma sfugge ancora un caso, il test 002

int costoInserimento,costoCancellazione,costoRimpiazzo,costoScambio;

int sourceIndexByCharacter[26];
int calcolaDistanza(string source, string target) {
if (source.length() == 0) {
  return target.length() * costoInserimento;
}
if (target.length() == 0) {
  return source.length() * costoCancellazione;
}


if (source[0]!= target[0]) {
  table[0][0] = min(costoRimpiazzo, costoCancellazione + costoInserimento);
}

sourceIndexByCharacter[((int)source[0])-97]=0;
for (int i = 1; i < source.length(); i++) {
  int deleteDistance = table[i - 1][0] + costoCancellazione;
  int insertDistance = (i + 1) * costoCancellazione + costoInserimento;
  int matchDistance = i * costoCancellazione + (source[i] == target[0] ? 0 : costoRimpiazzo);
  table[i][0] = min(min(deleteDistance, insertDistance),matchDistance);
}
for (int j = 1; j < target.length(); j++) {
  int deleteDistance = (j + 1) * costoInserimento + costoCancellazione;
  int insertDistance = table[0][j - 1] + costoInserimento;
  int matchDistance = j * costoInserimento + (source[0] == target[j] ? 0 : costoRimpiazzo);
  table[0][j] = min(min(deleteDistance, insertDistance),matchDistance);
}
for (int i = 1; i < source.length(); i++) {
  int maxSourceLetterMatchIndex = (source[i] == target[0] ? 0: -1);
  for (int j = 1; j < target.length(); j++) {
    int candidateSwapIndex = sourceIndexByCharacter[((int)target[j])-97];
    int jSwap = maxSourceLetterMatchIndex;
    int deleteDistance = table[i - 1][j] + costoCancellazione;
    int insertDistance = table[i][j - 1] + costoInserimento;
    int matchDistance = table[i - 1][j - 1];
    if (source[i] != target[j]) {
      if(costoRimpiazzo<costoCancellazione+costoInserimento){
        matchDistance+=costoRimpiazzo;
      }else{
        matchDistance+=costoCancellazione+costoInserimento;
      }

    } else {
      maxSourceLetterMatchIndex = j;
    }
    int swapDistance;
    if (candidateSwapIndex != 0 && jSwap != -1) {
      int iSwap = candidateSwapIndex;
      int preSwapCost;
      if (iSwap == 0 && jSwap == 0) {
        preSwapCost = 0;
      } else {
        preSwapCost = table[max(0, iSwap - 1)][max(0, jSwap - 1)];
      }
      swapDistance = preSwapCost + (i - iSwap - 1) * costoCancellazione + (j - jSwap - 1) * costoInserimento + costoScambio;
    } else {
      swapDistance = 999999;
    }
    table[i][j] = min(min(min(deleteDistance, insertDistance), matchDistance), swapDistance);
  }
  sourceIndexByCharacter[((int)source[i])-97]=i;

}
return table[source.length() - 1][target.length() - 1];
  }

int main(){

int i,j,N,M;
string NA;
string NB;
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
cin>>costoInserimento>>costoCancellazione>>costoRimpiazzo>>costoScambio;
cin>>NA>>NB;
cout<<calcolaDistanza(NA,NB)<<endl;
}

Il tuo codice sbaglia il secondo caso d’esempio:

2 4 10 3
ab
ba

Ho provato con questo (vedi le righe con il commento ///CONTROLLO AGGIUNTO), mi risolve il caso in questione ma salta comunque in test della piattaforma

int d[4002][4002];
int adiacenze[26];
int calcolaDistanza(string a, string target, int cIns, int cCanc, int cRim, int cSwap) {
    ///calcolo il costo nel caso in cui una delle due lettere risultasse vuota
    if (a.length() == 0) {
      return target.length() * cIns;
    }
    if (target.length() == 0) {
      return a.length() * cCanc;
    }

    ///nel caso in cui le prime due lettere risultassero differenti calcolo il costo minimo
    ///per farle divenire uguali ossia: il rimpiazzo o la cancallazione con inserimento
    if (a[0]!= target[0]) {
      d[0][0] = min(cRim, cCanc + cIns);
      if(a[0]==target[1]&&a[1]==target[0])     ///CONTROLLO AGGIUNTO
        d[0][0] = min(d[0][0], cSwap);
    }

    ///VALORIZZO la prima riga della matrice
    for (int i = 1; i < a.length(); i++) {
        int deleteDistance = d[i - 1][0] + cCanc;                                  ///costo precedente + cancellazione ultima lettera
        int insertDistance = (i +1 ) * cCanc + cIns;                   ///inserisco la corrente e le cancello tutte
        int matchDistance = i * cCanc + (a[i] == target[0] ? 0 : cRim);  ///cancello tutte le precedenti ed eseguo una sostituzione
        d[i][0] = min(min(deleteDistance, insertDistance),matchDistance);
    }
    ///VALORIZZO la prima colonna della matrice
    for (int j = 1; j < target.length(); j++) {
      int deleteDistance = (j + 1) * cIns + cCanc;                     ///inserisco tutte le lettere fino alla corrente e poi cancello l'ultima
      int insertDistance = d[0][j - 1] + cIns;                                      ///costo precedente + inserimento ultima lettera
      int matchDistance = j * cIns + (a[0] == target[j] ? 0 : cRim);      ///inserisco tutte le precedenti ed eseguo una sostituzione con l'ultima
      d[0][j] = min(min(deleteDistance, insertDistance),matchDistance);
    }

    adiacenze[((int)a[0])-97]=0;
    for (int i = 1; i < a.length(); i++) {
        ///verifico se la lettera corrente di A corrisponde alla prima lettera di B
        int maxSourceLetterMatchIndex = (a[i] == target[0] ? 0: -1);
        for (int j = 1; j < target.length(); j++) {
            int candidateSwapIndex = adiacenze[((int)target[j])-97];
            int jSwap = maxSourceLetterMatchIndex;
            int deleteDistance = d[i - 1][j] + cCanc;
            int insertDistance = d[i][j - 1] + cIns;
            int matchDistance = d[i - 1][j - 1];
            if (a[i] != target[j]) {
                    matchDistance+=cRim;
            } else {
                maxSourceLetterMatchIndex = j;
            }
            int swapDistance;
            if (candidateSwapIndex != 0 && jSwap != -1) {
                int iSwap = candidateSwapIndex;
                int preSwapCost=0;
                if (iSwap == 0 && jSwap == 0) {
                    preSwapCost = 0;
                } else {
                    preSwapCost = d[max(0, iSwap - 1)][max(0, jSwap - 1)];
                }
                swapDistance = preSwapCost + (i - iSwap - 1) * cCanc + (j - jSwap - 1) * cIns + cSwap;
            }else {
                swapDistance = 999999;
            }
            ///CONTROLLO AGGIUNTO
             if (i>=1 && j>=1 && a[i-1] == target[j] && a[i] == target[j-1]){
                if(i-1!=0 && j-1!=0){
                 swapDistance=   d[i-2][j-2]+cSwap;
            }else{
                 swapDistance=   d[i-1][j-1];
            }
                d[i][j] = min(min(min(deleteDistance, insertDistance), matchDistance), swapDistance);
             }else{
                d[i][j] = min(min(min(deleteDistance, insertDistance), matchDistance), swapDistance);
             }

        }
        adiacenze[((int)a[i])-97]=i;
    }
    return d[a.length() - 1][target.length() - 1];
}


int main(){
    int costoInserimento,costoCancellazione,costoRimpiazzo,costoScambio;
    int i,j,N,M;
    string NA;
    string NB;
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    cin>>costoInserimento>>costoCancellazione>>costoRimpiazzo>>costoScambio;
    cin>>NA>>NB;
    N=NA.size();
    M=NB.size();
    cout<<calcolaDistanza(NA,NB,costoInserimento,costoCancellazione,costoRimpiazzo,costoScambio)<<endl;

}

Sbaglia ancora il testcase riportato sopra:

Ok, penso d’aver capito il problema … spero di risolverlo :wink:
Grazie