Cod sursa(job #2588583)

Utilizator mehanixCiausu Nicoleta mehanix Data 24 martie 2020 23:21:22
Problema NFA Scor 30
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 12.5 kb
#include <iostream>
#include <map>
#include <vector>
#include <fstream>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;


typedef vector<map<char,vector<int> > > GRAF;

ifstream fin("nfa.in");
ofstream fout("nfa.out");

void adauga_arc(GRAF &graf, int q1, int q2, char c) {
    /// adauga nodului de start(q1) faptul ca litera "c" il trimite in nodul end(q2) //
    graf[q1][c].push_back(q2);
}

void afiseaza_graf(GRAF graf, int nr_stari) {
    ///itereaza prin noduri
    for(int i=0;i<=nr_stari;i++) {
        /// ia map-ul asociat nodului si itereaza-i prin chei
        cout<<"pentru "<<i<<"::\n";
        for(auto mp = graf[i].begin(); mp!= graf[i].end();++mp) {
            cout<<mp->first<<":{ ";
            //pentru fiecare cheie, iterez prin elem. din vectorul lui
            for(auto ends=mp->second.begin();ends!=mp->second.end();++ends) {
                cout<<*ends<<" ";
            }
            cout<<"}\n";

        }
    }
}

/**
 * Functie recursiva care traverseaza graful
 * word: cuvantul in sine
 * nod_curent: nodul la care a ajuns functia
 * i_char_curent: indicele caracterului la care a ajuns functia
 * i_char_final: indicele caracterului final
 * graf: graful automatului
 * stari_finale: vectorul de stari finale
 * */
int is_valid=0;
void verify(string& word, int nod_curent, int i_char_curent, const int i_char_final, GRAF& graf, int current_lg, vector<int>& stari_finale, vector<vector<bool>>& matrice_vizitati) {
    ///daca nu s-a mai ajuns aici cu lungimea asta, mergi pe aici///
	if(matrice_vizitati[nod_curent][current_lg] == false && is_valid == 0) {

        ///Daca am ajuns intr-un nod marcat ca nod final si la ultimul caracter din cuvant=> cuvant acceptat de automat
        if( i_char_curent == i_char_final )
            if(find(stari_finale.begin(), stari_finale.end(), nod_curent) != stari_finale.end())
            {
            	is_valid=1;
            }


        /// Verifica de unde poti pleca din nodul nod_curent cu caracterul word[i_char_curent] ///
        /// itereaza prin vectorul dat de graf[nod_curent][word[i_char_curent]] si reapeleaza functia cu caracterul urmator ///
        char c = word[i_char_curent];
            for(auto &ends : graf[nod_curent][c]) {
                if(matrice_vizitati[ends][current_lg] == false){
                    matrice_vizitati[ends][current_lg] = true;
                    verify(word, ends,i_char_curent+1, i_char_final, graf,current_lg+1, stari_finale, matrice_vizitati);
                }

            }
    }
}

bool is_accepting_state(int nod, vector<int>& stari_finale){
    return find(stari_finale.begin(), stari_finale.end(),nod)!=stari_finale.end();
}


vector<vector<pair<int,char>>> results;
void generate(GRAF& graf,int stare_initiala,vector<int>& stari_finale, vector<vector<bool>>& matrice_vizitati,int max_length){
      queue<vector<pair<int,char>> > q;
    vector<pair<int,char>> path;
    path.push_back(make_pair(stare_initiala,' '));

    q.push(path);
    path.clear();
    while (!q.empty()) {
        path = q.front();
        q.pop();
        pair<int,char> elem_p = path.back();
        int elem = elem_p.first;
        if(is_accepting_state(elem,stari_finale))
            results.push_back(path);
        if(matrice_vizitati[elem][path.size()] == false){
            for (auto &mp: graf[elem]) {
                for(auto ends=mp.second.begin();ends!=mp.second.end();++ends) {
                    vector<pair<int,char>>new_path(path);
                    if (results.size() < 100){
                        new_path.push_back(make_pair(*ends, mp.first));
                        q.push(new_path);
                        }
                }
            matrice_vizitati[elem][path.size()] = true;
            }
        }


    }


}

bool load_from_file(GRAF &graf, int &nr_stari, int &nr_tranzitii, int &stare_initiala, int &nr_stari_finale, vector<int>& stari_finale) {
        /// citire automat ///

    if(fin.good()) {
        fin>>nr_tranzitii;
        for(int i=0;i<nr_tranzitii;i++) {
            int q1, q2; char c;
            fin>>q1>>q2>>c;
            adauga_arc(graf, q1,q2,c);
        }

        fin>>stare_initiala;
        fin>>nr_stari_finale;

        stari_finale.resize(nr_stari_finale);
        for(int i=0;i<nr_stari_finale;i++) {
            fin>>stari_finale[i];
        }
    }
    else
        return false;
    return true;


}

bool load_big(GRAF &graf, int &nr_stari, int &nr_tranzitii, int &stare_initiala, int &nr_stari_finale, vector<int>& stari_finale){
    try {
        ///setup
        nr_stari = 3004;
        graf.resize(nr_stari+1);
        stare_initiala = 3001;
        nr_tranzitii = 0;
        nr_stari_finale=1;
        stari_finale.resize(nr_stari_finale);
        stari_finale[0] = 3004;
        ///adaug muchii 3001 - [1..1000] 'a' (1000)
        for(int i=1;i<=1000;i++) {
            nr_tranzitii++;
            adauga_arc(graf, 3001, i, 'a');
        }
        ///adaug muchii [1...1000] -> [1001...2000] 'b' (1mil)
        for(int i=1;i<=1000;i++)
            for (int j=1001;j<=2000;j++) {
                nr_tranzitii++;
                adauga_arc(graf,i,j,'b');
            }
        ///adaug muchii [1001-2000]...[2001-3000]'c' (1mil)
        for(int i=1001;i<=2000;i++)
            for (int j=2001;j<=3000;j++) {
                nr_tranzitii++;
                adauga_arc(graf,i,j,'c');
            }
        ///adaug muchii [2001-3000] - 3002 'd' (1000)
        for(int i=2001;i<=3000;i++) {
            nr_tranzitii++;
            adauga_arc(graf, i, 3002, 'd');
        }
        nr_tranzitii++;
        adauga_arc(graf,3000,3003,'d');
        nr_tranzitii++;
        adauga_arc(graf,3003,3004,'e');
    }
    catch (...) {
        return false;
    }
    return true;

}

int main()
{
    vector<int>stari_finale;
    vector<vector<bool>> matrice_vizitati;
    int nr_stari, nr_tranzitii, stare_initiala, nr_stari_finale;
    int choice=-1;
    bool status;
    GRAF graf;
    /**DECOMENTEAZA PENTRU VARIANTA CU INTERFATA IN LINIA DE COMANDA
    while(choice==-1){
        cout<<"Alege o optune:\n1.Incarca graf custom din fisier\n2.Incarca graful mare din cod (cel cu 3000 noduri si 2002002 muchii)\n\nScrie numarul optiunii alese:";
        cin>>choice;
        if (choice == 1) {
            fin>>nr_stari;
            graf.resize(nr_stari+1);
            status = load_from_file(graf, nr_stari, nr_tranzitii,stare_initiala,nr_stari_finale, stari_finale);
        }
        else if (choice == 2)
            status = load_big(graf, nr_stari, nr_tranzitii,stare_initiala,nr_stari_finale, stari_finale);
        else choice = -1;
    }


    string word;
    if (status == true) {
            cout<<"\nAutomat incarcat cu succes! :)"<<endl;
            choice=-1;
            while (choice == -1){
                cout<<"\nAlege o optiune:\n1.Testeaza apartenenta cuvintelor in automat\n2.Genereaza cele mai scurte 100 cuvinte acceptate de automat\n\nScrie numarul optiunii alese:";
                cin>>choice;
                if (choice == 1){

                while (true) {
                    cout<<"Introdu cuvantul de verificat:[sau EXIT pentru a iesi]"<<endl;
                    cin>>word;
                    if(word == "EXIT" || word =="exit")
                        break;
                    cout<<"Working on it...\n";

                    ///creez matrice vizitati pt cuv asta
                    ///lungimea max = lungimea cuvantului
                    matrice_vizitati.resize(nr_stari+1);
                    for(vector<bool> &v:matrice_vizitati) {
                        v.resize(word.length()+1);
                        for (auto&& x:v)
                            x=false;
                    }
                    verify(word,stare_initiala,0,word.length(),graf,0,stari_finale,matrice_vizitati);

                    if(is_valid)
                        cout<<"Cuvant acceptat de automat!\n";
                    else cout<<"Cuvant neacceptat de automat!\n";
                    is_valid=0;

                    }

                }
                else if (choice==2) {

                    /// reset matrice vizitati
                    matrice_vizitati.resize(nr_stari+1);
                    for(vector<bool> &v:matrice_vizitati) {
                        v.resize(100);
                        for (auto&& x:v)
                            x=false;
                    }
                    cout<<"Generez cuvintele acceptate... Please wait!\n";

                    generate(graf,stare_initiala,stari_finale,matrice_vizitati,100);
                    int cnt = 0;
                    for(auto x = results.begin();x< results.end(); x++){
                        if(cnt<100) {
                            cout<<"("<<++cnt<<"):";
                            for(auto &i:*x)
                                cout<<i.second;
                            cout<<'\n';
                        }

                    }
                }
            }
    }
    else {
        cout<<"Eroare la incarcarea/generarea automatului! :(\n";
    }

    	cout<<"Goodbye!";
    */

    /* Varianta "automata" ---- pentru testat pe InfoArena */
    fin>>nr_stari>>nr_tranzitii>>nr_stari_finale>>stare_initiala;
    stari_finale.resize(nr_stari_finale);
    int x=0;

    for(int i=0;i<nr_stari_finale;i++){
        fin>>x;
        stari_finale.push_back(x);
    }
    graf.resize(nr_stari+1);
    for(int i=0;i<nr_tranzitii;i++) {
            int q1, q2; char c;
            fin>>q1>>q2>>c;
            adauga_arc(graf, q1,q2,c);
        }
    fin>>x; string word;

    for(int i=0;i<x;i++) {
        fin>>word;
        is_valid=0;
        matrice_vizitati.resize(nr_stari+1);
        for(vector<bool> &v:matrice_vizitati) {
            v.resize(word.length()+1);
            for (auto&& x:v)
                x=false;
            }
        verify(word,stare_initiala,0,word.length(),graf,0,stari_finale,matrice_vizitati);

        if(is_valid)
            fout<<"1\n";
            else
            fout<<"0\n";

    }

}

/** VARIANTA DFS RECURSIVA - generare cuvinte
    Nu o mai folosesc deoarece nu e optima
    Dar o las aici pentru ca e totusi functionala
vector<string> results;
void generate(string word, int nod_curent, GRAF& graf, int current_lg, vector<int>& stari_finale, vector<vector<bool>>& matrice_vizitati,int max_length) {
    if(results.size()<=100){

    if(matrice_vizitati[nod_curent][current_lg] == false && word.length() <= max_length) {
        //cout<<"sunt la:"<<word<<' '<<nod_curent<<'\n';
        ///ia mapul asociat nodului
        ///itereaza prin litere
        for(auto mp = graf[nod_curent].begin(); mp!= graf[nod_curent].end();++mp) {
            ///adauga litera la cuvant
            //cout<<mp->first;

            ///Daca am ajuns intr-un nod marcat ca nod final => cuvant acceptat de automat

                /// Verifica de unde poti pleca din nodul nod_curent cu orice caracter ///
                /// itereaza prin vectorul dat de graf[nod_curent][char_curent] si reapeleaza functia cu caracterul urmator ///
                char c = mp->first;
                if(current_lg<=100) {
                for(auto &ends : graf[nod_curent][c]) {
                    word.push_back(c);

                        if(matrice_vizitati[ends][current_lg] == false){
                            cout<<"Plec pe "<<c<<" "<<ends<<endl;
                            matrice_vizitati[ends][current_lg] = true;
                            if(find(stari_finale.begin(), stari_finale.end(), ends) != stari_finale.end())
                                {
                                    cout<<"GASIT "<<":"<<word<<'\n';
                                    results.push_back(word);
                                }
                            generate(word, ends,graf,current_lg+1, stari_finale, matrice_vizitati,max_length);
                            matrice_vizitati[ends][current_lg] = false;
                            word.pop_back();
                        }
                    }


        }
    }

}
}
}       In main:

                 /*   ///incerc lungimi maxime pana gasesc una care imi genereaza ~ 100 elemente
                    ///daca nu exista, afisez toate cuvintele posibile
                    for(int i=1;i<=100 && results.size()<100; i++){
                        results.clear();
                        generate("",stare_initiala,graf,0,stari_finale,matrice_vizitati,i);
                    }

                    ///afisez cuvintele, in ordine inversa
                    int cnt = 1;
                    for (auto cuvant = results.rbegin(); cuvant != results.rend() && cnt <= 100; ++cuvant  ) {
                        cout<<"("<<cnt<<"):"<<*cuvant<<'\n';
                        cnt++;
                    }
*/