[Algoritmi] Togliere la ricorsione [c++] [RISOLTO VIC+APA!]

Messaggioda Giova411 » 22/04/2015, 22:11

Volevo esercitarmi per diletto e per non perdere la "mano"... :roll:
Anche perché questi sono esercizi classici nelle prove d'assunzione alla google, amazon e compagnia bella..
Avevo visto un esercizio del forum (IN STILE STRINGHE DEL DNA da confrontare) e pensavo di farlo ma è rimasto bloccato lì.
Consideriamo un dizionario con delle stringhe date ad esempio di 4 come questo:
AB BA ABB BAB
Data poi una stringa casuale come questa:
ABBBABABAB
Bisogna trovare se quest'ultima data è composta dalle sole stringhe del dizionario (anche ripetute)
Nell'esempio dovrei ottenere 3 modi possibili
(ossia tre modi: ABB − BA − BA − BAB, oppure ABB − BA − BAB − AB e ABB − BAB − AB − AB )

Sempre con lo stesso dizionario, ma dando una stringa diversa tipo questa:
ABBAAAB
Ottengo 0 modi.

Un codice ricorsivo che funziona l'ho scritto ma volevo sfruttare la programmazione dinamica o, per strafare, la tecnica memoization che memorizza solo cio' che ci serve.
Testo nascosto, fai click qui per vederlo
Codice:
#include <iostream>
#include <vector>
using namespace std;
string X;
vector < string > P;
int modi = 0;

void dfs (string s){
  if (s.length () >= X.length ()){
      if (s == X) modi++;
      return;
    }
  for (int i = 0; i < P.size (); i++){
      dfs (s + P[i]);
    }
}
int main (){
  int N;//numero di primitive
  cout << "Inserisci il numero di primitive: \n";
  cin >> N;
  string temp;
  cout << "Inserisci le primitive (separate da uno spazio): \n";
  for (int i = 0; i < N; i++){
      cin >> temp;
      P.push_back (temp);
    }
  cout << "Inserisci la stringa: \n";
  cin >> X;
  dfs ("");
  cout << "Numero: " << modi << endl;
}


Sono tornato a rompere :P :D
Ultima modifica di Giova411 il 27/04/2015, 19:03, modificato 1 volta in totale.
Giova411
Advanced Member
Advanced Member
 
Messaggio: 1783 di 2254
Iscritto il: 16/11/2006, 00:34

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda Giova411 » 23/04/2015, 10:40

Il codice che ho ideato che non funziona ma non trovo il bug.. Ma sento che la soluzione è ad un passo :oops:
Codice:
#include <iostream>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;

int dfs(string x, int n, vector < string >&S, int C[], string i, int k){
    if(i.length() > x.length()) {
        return 0;
    }
    if (i == x) { 
        return 1;
    }   
    for(int j=0; j< S.size(); j++){
     int cur = (k-1);                     
          if (cur <= n && x.substr( cur,S[j].size() ) == S[j] ){   
             C[k] = C[k-1] + dfs(x, n, S, C, i + S[j], cur+S[j].size()+1);     
               
      }
   }
   return C[k];
}

int main (){
  string X;
  vector < string > P;
  int N;//numero di primitive
  cout << "Inserisci il numero di primitive: \n";
  cin >> N;
  string temp;
  cout << "Inserisci le primitive (separate da uno spazio): \n";
  for (int i = 0; i < N; i++){
      cin >> temp;
      P.push_back (temp);
    }
  cout << "Inserisci la stringa: \n";
  cin >> X;
  int n = X.length();
  int C[n+1];
  string l = ""; 
  int k = 1;
  memset(C, 0,  sizeof(C)); 
  cout << "Numero: " << dfs (X, n, P, C, l, k) << endl;
}
Ultima modifica di Giova411 il 23/04/2015, 11:06, modificato 1 volta in totale.
Giova411
Advanced Member
Advanced Member
 
Messaggio: 1784 di 2254
Iscritto il: 16/11/2006, 00:34

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda apatriarca » 23/04/2015, 11:00

In questo momento non ho la possibilità di guardare il tuo codice. Volevo però dirti che non è necessario mettere il codice come spoiler. Si tratta in effetti di qualcosa di abbastanza centrale nella discussione per cui ha senso averlo visibile..
apatriarca
Moderatore
Moderatore
 
Messaggio: 3764 di 10438
Iscritto il: 08/12/2008, 20:37
Località: Madrid

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda Giova411 » 23/04/2015, 11:06

Mitico MITICOOOOOOO
(ora modifico il post, DANKE)
Giova411
Advanced Member
Advanced Member
 
Messaggio: 1785 di 2254
Iscritto il: 16/11/2006, 00:34

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda apatriarca » 23/04/2015, 11:14

Solo un altro piccolo commento. Se mai facessi un colloquio in cui ti chiedono di risolvere un problema di questo tipo, non strafare.. A meno che non ti venga espressamente richiesto, implementa la versione più semplice che ti viene in mente. Nella maggior parte dei casi lo scopo di questi test è quello di verificare se sai realizzare dei semplici programmi, non tanto vedere se sai arrivare ad una soluzione elegante ed efficiente. Se proprio ci tieni a far vedere che conosci anche metodi più complicati puoi sempre dirlo a voce.
apatriarca
Moderatore
Moderatore
 
Messaggio: 3765 di 10438
Iscritto il: 08/12/2008, 20:37
Località: Madrid

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda Giova411 » 23/04/2015, 11:24

Apa mi mancavi e son tornato a scrivere anche per imparare da te.
Sì, nella fattispecie, questo è un esercizio che si risolve magari con 3 cicli.
L'ho preso proprio da una discussione che avevi risolto ad Hamming cambiando però le richieste =)
L'avevo lasciato lì ma ora voglio risolverlo per SFIZIO
(spero col tuo aiuto o chiunque voglia risolvere questi PUZZLE :roll: :) )
Giova411
Advanced Member
Advanced Member
 
Messaggio: 1786 di 2254
Iscritto il: 16/11/2006, 00:34

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda vict85 » 23/04/2015, 12:28

Ci sono delle problematiche del tuo codice.

Il primo è l'aver aggiunto una libreria che neanche stai usando: cmath .
Il secondo è di aver usato i VLA in un codice C++, ovvero hai usato codice non standard. Cosa che non hai notato perché non hai messo tra le opzione del compilatore -pedantic, -Wpedantic o -Wvla-extension (insieme a -std=c++11) e il tuo compilatore, gcc immagino, possiede i VLA come estensione del C++. Tra l'altro la soluzione consigliata in campo C++ è quella di usare un vector (che stai già usando ovunque) e che avrebbe reso inutile l'uso di memset, e pertanto anche di cstring.

Penso sia inoltre importante osservare che il numero di lettere dell'alfabeto è molto ridotto (2 in questo caso, 4 nel caso del DNA). Questo permette di usare strutture dati particolari per memorizzare il dizionario in modo compatto. Penso sia inoltre utile ordinare adeguatamente il dizionario per eliminare test inutili.

Mi sembra che in generale manchino nel tuo codice dei test per eliminare i rami inutili. Insomma generati tutte le combinazioni anche se è inutile.
vict85
Cannot live without
Cannot live without
 
Messaggio: 7694 di 19254
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda Giova411 » 23/04/2015, 12:43

Eh si Vic ho fatto un po' di cavolate nella seconda versione.
Ad esempio memset l'avevo usata per poi toglierla e mi son dimenticato.
Era una prova da battaglia con molti cout sparsi.
Fermo rimane il primo "pensiero ricorsivo" vedi il primo codice nello spoiler.
Da lì io vorrei arrivare ad usare la tecnica memoization per non sballare troppo di entry il pc con stringhe molto più lunghe.
Il primo l'avevo scritto di botto ma la tecnica memoization (pur avendo superato bene l'esame di Algo) non l'ho mai digerita...
(come puoi immaginare anche la PD, che comprende la suddetta tecnica, non mi è mai entrata bene)

PS: Pensi al PRUNING quindi col backtrack?
Giova411
Advanced Member
Advanced Member
 
Messaggio: 1787 di 2254
Iscritto il: 16/11/2006, 00:34

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda apatriarca » 23/04/2015, 14:01

Credo tu stia in un certo senso risolvendo il problema sbagliato. Ti viene infatti chiesto se la stringa può essere scritta con le solo sottostringhe dell'alfabeto, non di calcolare il numero di possibili modi per farlo. Cercando il numero di modi stai insomma facendo molti più calcoli del necessario. Il problema originale può essere risolto in tempo lineare. Non è affatto necessario ricorrere a tecniche come la memoization.

Consideriamo il tuo esempio. Tu hai le sottostringhe AB, BA, ABB e BAB. Ogni stringa composta da queste sottostringhe sarà quindi della forma ((AB|BA)B?)* usando le espressioni regolari.. Un metodo di risoluzione potrebbe quindi essere quello di generare un NDA (o DFA) che risolve questo problema. La versione più semplice potrebbe essere quella di mantenere un insieme di stati possibili e di aggiornare questi stati man mano che leggi la stringa. Il numero massimo di stati sarà uguale al numero di sottostringhe (ma solo se non ottimizzi l'automa). Se il numero di stati possibili arriva a zero prima di raggiungere la fine della stringa (o la stringa finisce quando nessuno degli stati è alla fine della stringa) vuol dire che la risposta è negativa. In caso contrario è positiva.
apatriarca
Moderatore
Moderatore
 
Messaggio: 3767 di 10438
Iscritto il: 08/12/2008, 20:37
Località: Madrid

Re: [Algoritmi, memoization?] Togliere la ricorsione [c++]

Messaggioda Giova411 » 23/04/2015, 14:10

Io volevo contare i modi e non solo dire se è vero o falso.
Se fai partire il primo mio codice, ti dice quanti modi hai per formare la stringa in base alle stringhe del dizionario dato.
Quindi devo tornre il numero delle permutazioni. Dici si possa fare in O(n) ? Al più O(n m) :smt012
Giova411
Advanced Member
Advanced Member
 
Messaggio: 1788 di 2254
Iscritto il: 16/11/2006, 00:34

Prossimo

Torna a Informatica

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite