Cod sursa(job #2821942)

Utilizator monicaandreea46Girbea Monica monicaandreea46 Data 23 decembrie 2021 13:02:08
Problema Parcurgere DFS - componente conexe Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 27.36 kb
#include <bits/stdc++.h>
#include<fstream>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>

int n, m, a, b,c, s;

class graf{
public:
    //int mat[101][101];
    std::vector< std::vector<int> > lista;
    std::vector< std::vector< std::pair<int, int>> > lista_cost;
    std::vector< std::pair<int, int> > muchii;

    void solve_DFS_componente_conexe();
    void solve_bfs();
    void solve_sortare_topologica();
    void solve_havel_hakimi();
    void solve_comp_tare_conex();
    void solve_biconex();
    void solve_disjoint();
    void solve_kruskal();
    void solve_dijkstra(int start);
    void solve_bellmanford();
    void solve_royfloyd();
    void solve_darb();
    void solve_maxflow();
    void solve_euler();
    void solve_hamilton();

private:
    void new_mat( int nod1, int nod2);
    void new_lista( int nod1, int nod2);
    void new_lista_orientat(int nod1, int nod2);
    void new_lista_cost( int nod1, int nod2, int cost);
    void new_lista_cost_neorientat(int nod1, int nod2, int cost);
    void new_muchii( int nod1, int nod2);

    void afisare_mat(std::ostream &fg);
    void afisare_lista();
    void afisare_lista_cost();
    void afisare_muchii();
    void sortare_lista();

    void dfs(int nod, std::vector<bool> &viz);

    void bfs(int nod, std::vector<bool> &viz, std::vector<int> &dist);

    void dfs_sortare_topologica(int nod, std::deque<int> &coada, std::vector<int> &viz);

    bool havel_hakimi_verificare(std::vector<int> &secv);

    void dfs_comp_tare_conex(int nod, int &nr_comp_conex, std::vector<int> &low, std::vector<int> &membru, std::vector<int> &viz,
                        std::vector<std::vector<int> > &componente, std::deque<int> &st);

    void dfs_biconex(int nod, int &nr_comp_biconex, std::vector<int> &viz, std::vector<int> &low, std::vector<int> &tata,
                     std::deque<int> &st, std::deque<std::pair<int, int>> &perechi,
                     std::vector<std::set<int>> &componente);


    int find_set(int nod, std::vector<int> &tata);
    void union_set(int nod1, int nod2, std::vector<int> &tata, std::vector<int> adancime);

    void royfloyd();

    std::pair<int, int> BFS_darb(int start);

    int BFS_maxflow(int start, int dest, std::vector<int> &tata, std::vector<std::vector<int>> &cap);

    void dijkstra(int start, std::vector<int> &dist);

    void bellmanford(int start, std::vector<int> &dist, bool neg);

    void kruskal(std::vector<std::pair<int, std::pair<int, int>>> &apm,
            std::vector<std::pair<int, std::pair<int, int>>> &muchii, int &sum);

    int hamilton(int conf, int stop, std::vector<std::vector<int>> &cost, int C[262150][20]);


};

void graf::new_mat(int nod1, int nod2) {
    mat[nod1-1][nod2-1] = 1;
    mat[nod2-1][nod1-1] = 1;
}

void graf::new_lista(int nod1, int nod2){
    lista[nod1].push_back(nod2);
    lista[nod2].push_back(nod1);
}

void graf::new_lista_orientat(int nod1, int nod2){
    lista[nod1].push_back(nod2);
}

void graf::new_lista_cost(int nod1, int nod2, int cost) {
    lista_cost[nod1].push_back(std::make_pair(nod2, cost));
}

void graf::new_lista_cost_neorientat(int nod1, int nod2, int cost) {
    lista_cost[nod1].push_back(std::make_pair(nod2, cost));
    lista_cost[nod2].push_back(std::make_pair(nod1, cost));
}

void graf::new_muchii( int nod1, int nod2) {
    muchii.push_back( std::make_pair(nod1, nod2) );
}

void graf::sortare_lista() {
    for(auto i=1 ; i<n+1 ; i++)
        std::sort(lista[i].begin(), lista[i].end());
}

void graf::afisare_mat(std::ostream& fg) {
    for(auto i=0; i<n; i++){
        for(auto j=0 ; j<n; j++){
            fg<<mat[i][j]<<" ";
        }
        fg<<"\n";
    }
}

void graf::afisare_lista() {
    for(auto i=1 ; i<n+1 ; i++){
        std::cout<<i<<" : ";
        for(auto j=0 ; j<lista[i].size(); j++)
            std::cout<<lista[i][j]<<" ";
        std::cout<<"\n";
    }

    std::cout<<"\n";
}

void graf::afisare_lista_cost() {
    for(auto i=0 ; i<n ; i++){
        std::cout<<i<<" - ";
        for( auto j = lista_cost[i].begin() ; j != lista_cost[i].end(); j++){
            std::cout<<" ( "<< j->first<<" , "<<j->second<<" ) ";
        }
        std::cout<<"\n";
    }

    std::cout<<"\n";
}

void graf::afisare_muchii(){
    for(auto i=0 ; i<muchii.size(); i++)
        std::cout<<muchii[i].first<<" "<<muchii[i].second<<"\n";
    std::cout<<"\n";
}


void graf::dfs(int nod, std::vector<bool> &viz){
    viz[nod] = true;
    //std::cout<<nod<<" ";

    for( auto i = lista[nod].begin(); i != lista[nod].end(); i++)
        if(!viz[*i]) dfs(*i, viz);
}

//O(n + m)

void graf::solve_DFS_componente_conexe() {
    std::ifstream f("dfs.in");
    std::ofstream fg("dfs.out");

    std::vector< bool> viz;
    std::vector<int> v;

    f>>n>>m;

    for(auto i = 0 ; i<=n ; i++) {
        viz.push_back(false);
        lista.push_back(v);
    }

    for(int i=0 ; i<m ; i++){
        f>>a>>b;
        new_lista(a,b);
    }

    int cnt = 0;
    for(auto i = 0 ; i<n ; i++ )
        if( !viz[i] ){
            cnt++;
            dfs(i, viz);
        }

    fg<< cnt;
}

void graf::bfs(int nod, std::vector< bool> &viz, std::vector< int> &dist){
    std::queue<int> coada;
    viz[nod] = true;
    dist[nod] = 0;
    coada.push(nod);

    while(!coada.empty()){
        int vecin = coada.front();
        //std::cout<<vecin<<" ";
        coada.pop();

        for( auto i = lista[vecin].begin() ; i != lista[vecin].end(); i++){
            if( !viz[*i] ){
                viz[*i] = true;
                coada.push(*i);
                dist[*i] = dist[vecin] + 1;
            }
        }
    }
}

//O(m + n)

void graf::solve_bfs(){
    std::ifstream f("bfs.in");
    std::ofstream fg("bfs.out");

    std::vector< bool> viz;
    std::vector<int> dist;
    std::vector<int> v;

    f>>n>>m>>s;

    for(auto i = 0 ; i<=n ; i++) {
        viz.push_back(false);
        dist.push_back(-1);
        lista.push_back(v);
    }

    for(int i=0 ; i<m ; i++){
        f>>a>>b;
        new_lista_orientat(a,b);
    }

    bfs(s, viz, dist);

    for(int i = 1; i <= n; i++)
        fg<<dist[i]<<" ";

}

void graf::dfs_sortare_topologica(int nod, std::deque<int> &coada, std::vector<int> &viz){
    static int cnt = 0;
    viz[nod] = ++cnt;

    for( auto i = lista[nod].begin(); i != lista[nod].end(); i++) {
        if (viz[*i] == -1) dfs_sortare_topologica(*i, coada, viz);
    }

    coada.push_back(nod);
}

// O(n + m)
// la intoarcerea din dfs, adaugam nodul intr-o coada

void graf::solve_sortare_topologica(){
    std::ifstream f("sortaret.in");
    std::ofstream fg("sortaret.out");

    std::vector<int> viz;
    std::deque<int> coada;
    std::vector<int> v;

    f>>n>>m;

    for(auto i = 0 ; i<=n ; i++){
        viz.push_back(-1);
        lista.push_back(v);
    }

    for(int i=0 ; i<m ; i++){
        f>>a>>b;
        new_lista(a-1,b-1);
    }

    for(int i = 0 ; i< n ; i++){
        if(viz[i] == -1) dfs_sortare_topologica(i, coada, viz);
    }

    while(!coada.empty()){
        int aux = coada.back();
        fg<<aux + 1<<" ";
        coada.pop_back();
    }
}

bool graf::havel_hakimi_verificare(std::vector<int> &secv){
    int sum= 0, ok=1, nr;
    for( auto i = secv.begin() ; i!=secv.end() ; i++){
        sum += *i;
        if(*i >= n) ok = 0;
    }

    if(sum%2 != 0 || ok ==0) return false;

    while(ok){
        sort(secv.begin(), secv.end(), std::greater<>());

        if(secv[0] == 0) return true; //toate elementele sunt 0 daca cel mai mare e 0

        int cnt = secv[0];
        secv.erase(secv.begin()); //sterg primul elem

        if( cnt  > secv.size()) return false; //verific ca nu ies din secventa

        for(int i= 0; i< cnt ; i++){
            secv[i]--;

            if(secv[i] < 0) return false;

        }

        for( auto i = secv.begin() ; i!=secv.end() ; i++)
            std::cout<<*i<<" ";
        std::cout<<"\n";

    }
return true;
}

// O( n^2 * log n)

void graf::solve_havel_hakimi(){
    std::ifstream f("hh.in");
    std::ofstream fg("hh.out");
    std::vector<int> secv;
    f>>n;
    for(int i = 0 ; i<n ; i++){
        f>>a;
        secv.push_back(a);
    }

    if(havel_hakimi_verificare(secv)) std::cout << "DA";
    else std::cout<<"NU";

}

void graf::dfs_comp_tare_conex(int nod, int &nr_comp_conex, std::vector<int> &low, std::vector<int> &membru, std::vector<int> &viz,
                          std::vector<std::vector<int> > &componente, std::deque<int> &st){
    static int cnt = 0;
    viz[nod] = ++cnt;
    low[nod] = cnt;
    st.push_back(nod);
    membru[nod] = 1;

    for( auto i = lista[nod].begin(); i != lista[nod].end(); i++) {
        if (viz[*i] == -1) {
            dfs_comp_tare_conex(*i, nr_comp_conex, low, membru, viz, componente, st);
            low[nod] = fmin(low[nod], low[*i]);
        } else if (membru[*i] == 1) {
            low[nod] = fmin(low[nod], viz[*i]);
        }
    }

    int aux = 0;
    if(low[nod] == viz[nod]){

        std::vector<int>v;
        componente.push_back(v);

        while(st.back() != nod){
            aux = st.back();
            //std::cout<< aux<<" ";

            componente[nr_comp_conex].push_back(aux);
            membru[aux] = 0;
            st.pop_back();
        }

        aux = st.back();
        //std::cout<< aux<<"\n ";
        componente[nr_comp_conex].push_back(aux);
        membru[aux] = 0;
        st.pop_back();

        ++nr_comp_conex;
    }

}

// O(n+m)
// o componenta este tare conexa daca exista cel putin un drum de la un nod la oricare altul
// ne folosim de doi vectori:
// low: reprezinta nodul de grad cel mai mic la care nodul curent poate ajunge
// viz: ordinea in care am vizitat nodurile (gradul)
// cand ne intoarcem din dfs, daca low[vecin] == low[nod curent] => componenta tare conexa

void graf::solve_comp_tare_conex(){
    std::ifstream f("ctc.in");
    std::ofstream fg("ctc.out");

    std::vector<int> viz;
    std::vector<int> low;
    std::vector<int> membru;
    std::deque<int> st;
    std::vector< std::vector<int> > componente;

    int nr_comp_conex = 0;

    f>>n>>m;

    std::vector<int> v;
    for(auto i = 0 ; i<=n ; i++){
        viz.push_back(-1);
        low.push_back(-1);
        membru.push_back(0);
        lista.push_back(v);
    }

    for(int i=0 ; i<m ; i++){
        f>>a>>b;
        new_lista_orientat(a-1,b-1);
    }

    for(int i = 0 ; i< n ; i++){
        if(viz[i] == -1) dfs_comp_tare_conex(i, nr_comp_conex, low, membru, viz, componente, st);
    }

    fg<<nr_comp_conex<<"\n";

    for(int i= 0 ; i<nr_comp_conex ; i++){
        for(auto j= componente[i].begin(); j!=componente[i].end(); j++)
            fg<<*j + 1<<" ";
        fg<<"\n";
    }

}

void graf::dfs_biconex(int nod, int &nr_comp_biconex, std::vector<int> &viz, std::vector<int> &low, std::vector<int> &tata,
                       std::deque<int> &st, std::deque<std::pair<int, int>> &perechi,
                       std::vector<std::set<int>> &componente ){
    static int cnt = 0;
    std::set<int> s;
    viz[nod] = ++cnt;
    low[nod] = cnt;
    st.push_back(nod);
    int nr_copii = 0;

    for( auto i = lista[nod].begin(); i != lista[nod].end(); i++) {
        if (viz[*i] == -1) {
            tata[*i] = nod;
            nr_copii++;
            perechi.push_back(std::make_pair(nod, *i));

            dfs_biconex(*i, nr_comp_biconex, viz, low, tata, st, perechi, componente );

            low[nod] = fmin(low[nod], low[*i]);

            if ( low[*i] >= viz[nod]) { //e punct de articulatie
                componente.push_back(s);

                while (perechi.back().first != nod || perechi.back().second != *i) {
                    componente[nr_comp_biconex].insert(perechi.back().first);
                    componente[nr_comp_biconex].insert(perechi.back().second);
                    perechi.pop_back();
                }
                componente[nr_comp_biconex].insert(perechi.back().first);
                componente[nr_comp_biconex].insert(perechi.back().second);
                perechi.pop_back();

                ++nr_comp_biconex;

            }

        } else if (*i != tata[nod]) {
            low[nod] = fmin(low[nod], viz[*i]);
        }
    }

}

//o(m + n)
// o componenta este biconexa daca exista un ciclu intre oricare doua noduri
// ne folosim de doi vectori:
// low: reprezinta nodul de grad cel mai mic la care nodul curent poate ajunge
// viz: ordinea in care am vizitat nodurile (gradul)
// cand ne intoarcem din dfs, daca low[vecin] >= low[nod curent] => punct de articulatie => componenta biconexa

void graf::solve_biconex(){
    std::ifstream f("biconex.in");
    std::ofstream fg("biconex.out");

    std::vector<std::set<int>> componente;
    std::vector<int> viz;
    std::vector<int> low;
    std::vector<int> tata;
    std::deque<int> st;
    std::deque<std::pair<int, int>> perechi;
    std::vector<int> v;
    int nr_comp_biconex = 0;

    f>>n>>m;

    for(auto i = 0 ; i<=n ; i++) {
        viz.push_back(-1);
        low.push_back(-1);
        tata.push_back(-1);
        lista.push_back(v);
    }

    for(int i=0 ; i<m ; i++){
        f>>a>>b;
        new_lista(a-1,b-1);
    }

    for(int i = 0 ; i< n ; i++){
        if(viz[i] == -1) dfs_biconex(i, nr_comp_biconex, viz, low, tata, st, perechi, componente );
    }

    fg<<nr_comp_biconex<<"\n";

    for(int i = 0 ; i<nr_comp_biconex ; i++){
        for(auto j = componente[i].begin() ; j != componente[i].end() ; j++)
            fg<< *j + 1<<" ";
        fg<<"\n";
    }

}

int graf::find_set(int nod, std::vector<int> &tata) {
    if( nod == tata[nod])  return nod;
    return tata[nod] =  find_set(tata[nod], tata);
}

void graf::union_set(int nod1, int nod2, std::vector<int> &tata, std::vector<int> adancime){
    nod1 = find_set(nod1, tata);
    nod2 = find_set(nod2, tata);

    if(nod1 != nod2) {
        if( adancime[nod1] < adancime[nod2]) std::swap( nod1, nod2);

        tata[nod2] = nod1;

        if(adancime[nod1] == adancime[nod2]) adancime[nod1]++;
    }
}

// O(log n) pentru union
// o(1) pentru verificare
// pentru union => gasim tatal fiecarui nod, daca sunt diferiti unim arborele mai mic la cel mai mare
// pentru verificare => gasim tatal fiecarui nod si comparam

void graf::solve_disjoint(){
    std::ifstream f("disjoint.in");
    std::ofstream fg("disjoint.out");

    std::vector<int> tata;
    std::vector<int> adancime;
    int op;

    f>>n>>m;

    for(auto i = 0 ; i<=n ; i++){
        tata.push_back(i);
        adancime.push_back(0);
    }

    for(int i=0 ; i<m ; i++){
        f>>op>>a>>b;

        if(op == 1){
            union_set(a, b, tata, adancime);
        }

        if(op == 2){
            a = find_set(a, tata);
            b = find_set(b, tata);

            if(a!=b) fg<<"NU\n";
            else fg<<"DA\n";
        }
    }

}

void graf::kruskal(std::vector< std::pair< int, std::pair<int, int>> > &apm, std::vector< std::pair< int, std::pair<int, int>> > &muchii, int &sum){
    std::vector<int> id;

    for(auto i=0 ; i<n ; i++){
        for( auto j = lista_cost[i].begin() ; j != lista_cost[i].end(); j++){
            muchii.push_back( std::make_pair( j->second, std::make_pair(i, j->first)) );
        }

        id.push_back(i);
    }

    std::sort(muchii.begin() , muchii.end());

    for(auto i = muchii.begin() ; i!= muchii.end() ; i++){
        if( id[i->second.first] != id[i->second.second] ){
            sum = sum + i->first;
            apm.push_back( *i );

            int id_vechi = id[i->second.first];
            int id_nou = id[i->second.second];

            for(int i = 0 ; i<n ; i++){
                if( id[i] == id_vechi ) id[i] = id_nou;
            }
        }
    }
}

// O(m log(n) + m log(n))
// am reorganizat muchiile ( cost, (nod1, nod2)) si le-am sortat
// pentru fiecare muchie vedem daca capetele sunt in componente conexe diferite
// caz in care, adaugam muchia in arbore si punem toate nodurile din componenta veche in cea noua

void graf::solve_kruskal() {
    std::ifstream f("apm.in");
    std::ofstream fg("apm.out");

    std::vector< std::pair< int, std::pair<int, int>> > muchii;
    std::vector< std::pair< int, std::pair<int, int>> > apm;
    std::vector< std::pair<int, int>> p;
    int sum = 0;

    f>>n>>m;

    for( int i=0 ; i<n ; i++){
        lista_cost.push_back(p);
    }

    for(int i=0 ; i<m ; i++){
        f>>a>>b>>c;
        new_lista_cost_neorientat(a-1, b-1, c);
    }

    kruskal(apm,muchii, sum);

    fg<<sum<<"\n"<<apm.size()<<"\n";

    for(auto i = apm.begin() ; i!= apm.end() ; i++) {
        fg<<i->second.first + 1<<" "<<i->second.second + 1<<"\n";
    }


}

void graf::bellmanford(int start, std::vector<int> &dist, bool neg){
    std::vector<bool> viz;
    std::vector<int> ord;
    std::queue<int> coada;

    for( int i=0 ; i<n ; i++)
    {
        viz.push_back(false);
        ord.push_back(0);
    }

    dist[start] = 0;
    coada.push(start);
    viz[start] = true;

    while(!coada.empty() && !neg) {
        int nod = coada.front();
        coada.pop();
        viz[nod] = false;

        for (auto i = lista_cost[nod].begin(); i != lista_cost[nod].end(); i++) {

            if (dist[nod] < INT_MAX) {

                int vecin = i->first;
                int cost = i->second;

                if (dist[vecin] > dist[nod] + cost) {
                    dist[vecin] = dist[nod] + cost;

                    if (!viz[vecin]) {
                        if( ord[vecin] > n) neg = true; // detecteaza ciclu neg
                        else{
                            coada.push(vecin);
                            viz[vecin] = true;
                            ord[vecin]++;
                        }
                    }
                }
            }
        }
    }
}

// O(m*n)
// Similar cu dijkstra doar ca functioneaza pe numere negative
// avem un vector de distanta si o coada
// adaugam nodurile a caror distanta a fost modificata in coada si verificam vecinii
// pentru ciclu negativ tinem cont de cate ori a fost vizitat un nod (depaseste n => ciclu)

void graf::solve_bellmanford(){
    std::ifstream f("bellmanford.in");
    std::ofstream fg("bellmanford.out");

    std::vector<int> dist;
    std::vector< std::pair<int, int>> p;
    bool neg = false;

    f>>n>>m;

    for( int i=0 ; i<n ; i++)
    {
        dist.push_back(INT_MAX);
        lista_cost.push_back(p);
    }

    for(int i=0 ; i<m ; i++){
        f>>a>>b>>c;
        new_lista_cost(a-1, b-1, c);
    }

    bellmanford(0, dist, neg);

    if(neg) fg<<"Ciclu negativ!";
    else
    {
        for(auto i=1 ; i<n ; i++) {
            fg<<dist[i]<<" ";
        }
    }

}

void graf::dijkstra(int start, std::vector<int> &dist){
    dist[start] = 0;

    std::set<std::pair<int, int>> s;

    s.insert( std::make_pair(start, 0));

    while(!s.empty()){
        int nod = s.begin()->second;

        s.erase(s.begin());

        for(auto i = lista_cost[nod].begin() ; i != lista_cost[nod].end(); i++){
            int vecin = i->first;
            int cost = i->second;

            if(dist[vecin] > dist[nod] + cost){
                s.erase(std::make_pair(dist[vecin], vecin));
                dist[vecin] = cost + dist[nod];
                s.insert(std::make_pair(dist[vecin], vecin));
            }
        }
    }
}

// O(mlogn)
// avem un vector de distante si un set
// in set tinem perechi de (nod, distanta) unde se afla nodurile care au fost modificate
// pentru care verificam pe rand vecinii pentru a vedea daca se pot modifica si acestia

void graf::solve_dijkstra(int start){
    std::ifstream f("dijkstra.in");
    std::ofstream fg("dijkstra.out");

    f>>n>>m;

    std::vector<int> tata;
    std::vector<int> dist;
    std::vector<bool> viz;
    std::vector< std::pair<int, int>> p;

    for( int i=0 ; i<n ; i++)
    {
        dist.push_back(INT_MAX);
        viz.push_back(false);
        tata.push_back(-1);
        lista_cost.push_back(p);
    }

    for(int i=0 ; i<m ; i++){
        f>>a>>b>>c;
        new_lista_cost(a-1, b-1, c);
    }

    dijkstra(start, dist);

    for(int i = 0; i<n ; i++)
    {
        if(i!= start){
            if(dist[i] == INT_MAX) fg<<"0 ";
            else fg<<dist[i]<<" ";
        }

    }

}

void graf::royfloyd(){
    for(int i=0 ; i<n; i++)
        for(int j=0 ; j<n; j++)
            for(int k=0 ; k<n; k++)
                if(mat[j][i] && mat[i][k] && (mat[j][k] > mat[j][i] + mat[i][k] || !mat[j][k]) && j!=k)
                    mat[j][k] = mat[j][i] + mat[i][k];
}

// O(n^3)

void graf::solve_royfloyd() {
    std::ifstream f("royfloyd.in");
    std::ofstream fg("royfloyd.out");

    f>>n;

    for( int i=0 ; i<n ; i++){
        for( int j=0 ; j<n ; j++){
            f>>a;
            mat[i][j] = a;
        }
    }

    royfloyd();

    afisare_mat( fg);

}

std::pair<int, int> graf::BFS_darb(int start){
    std::vector<int> v;
    std::vector<int> viz;
    std::vector<int> dist;
    std::queue<int> coada;
    int diametru;
    int dest;

    for(int i = 0; i<n ; i++){
        viz.push_back(-1);
        dist.push_back(0);
    }

    viz[start] = 1;
    coada.push(start);
    dist[start] = 1;

    while( !coada.empty()){
        int nod = coada.front();
        coada.pop();

        for(auto vecin = lista[nod].begin() ; vecin != lista[nod].end(); vecin++){
            if(viz[*vecin] == -1){
                coada.push(*vecin);
                viz[*vecin] = 1;
                dist[*vecin] = dist[nod] + 1;

                diametru = dist[*vecin];
                dest = *vecin;
            }
        }
    }

    return std::make_pair(diametru, dest);
}

//O(n)
// doua parcurgeri, prima din nodul 0 si a 2a din ultimul nod in care a ajuns prima parcurgere

void graf::solve_darb() {
    std::ifstream f("darb.in");
    std::ofstream fg("darb.out");

    f>>n;

    std::vector<int> v;
    int diametru, dest ;
    std::pair<int, int> s;

    for(int i = 0; i<n ; i++){
        lista.push_back(v);
    }

    for( int i=0 ; i<n-1 ; i++){
        f>>a>>b;
        lista[a-1].push_back(b-1);
        lista[b-1].push_back(a-1);
    }

    s = BFS_darb(0);
    dest = s.second;
    s = BFS_darb(dest);
    diametru = s.first;
    fg<<diametru;

}

int graf::BFS_maxflow(int start, int dest, std::vector<int> &tata, std::vector<std::vector<int>> &cap){
    std::queue<std::pair<int, int>> coada;
    for(int i=0 ; i<n ; i++){
        tata[i] = -1;
    }

    tata[start] = -2;

    coada.push(std::make_pair(start, INT_MAX));

    while(!coada.empty()){

        int nod = coada.front().first;
        int flux = coada.front().second;
        coada.pop();

        for(auto vecin = lista[nod].begin(); vecin != lista[nod].end(); vecin++){
            //std::cout<<nod<<" "<<*vecin<<" "<<cap[nod][*vecin]<<"\n";
            if( tata[*vecin] == -1 && cap[nod][*vecin] >0){
                tata[*vecin] = nod;

                int flux_nou = std::min(flux, cap[nod][*vecin]);

                if( *vecin == dest) return flux_nou;

                coada.push(std::make_pair(*vecin, flux_nou));
            }
        }
    }
    return 0;
}

//O( n * m^2) (Edmonds-Karp)
// verificam fluxuri noi cu un bfs
// adaugam acest flux la cele gasite si actualizam matricea de capacitate

void graf::solve_maxflow() {
    std::ifstream f("maxflow.in");
    std::ofstream fg("maxflow.out");

    f>>n>>m;

    std::vector<std::vector<int> > cap;
    std::vector<int> tata(n,0);
    std::vector<int> v(n,0);
    std::vector<int> l;
    int start=0;
    int dest=n-1;

    for(auto i = 0; i<n ; i++){
        lista.push_back(l);
        cap.push_back(v);
    }

    for( int i=0 ; i<m ; i++){
        f>>a>>b>>c;
        lista[a-1].push_back(b-1);
        cap[a-1][b-1] = c;
    }

    int flux = 0;

    int flux_nou = BFS_maxflow(start, dest, tata, cap);
    while(flux_nou){

        flux += flux_nou;
        int nod = dest;

        while(nod != start){
            int t = tata[nod];
            cap[t][nod] -= flux_nou; //actualizezi flowul gasit  + muchiile de intoarcere
            cap[nod][t] += flux_nou;
            nod = t;
        }


        flux_nou = BFS_maxflow(start, dest, tata, cap);
    }

    fg<<flux;

}


// O( n + m )
// Un ciclu se numeste eulerian daca parcurge toate muchiile o singura data
// avem un vector de muchii care retine (nod1, nod2)
// o lista, unde pentru fiecare nod avem ce muchii ii apartine (1: 2, 5, 6 inseamna nodul 1 apartine muchiei 2, 5, 6)
// si un vector used sa stim daca am folosit muchia de indice i
// generam un ciclu aleator, iar la intoarcere generam si ciclurile din muchhile ramase

void graf::solve_euler() {
    std::ifstream f("ciclueuler.in");
    std::ofstream fg("ciclueuler.out");

    f>>n>>m;

    std::stack<int> s;
    std::vector<std::pair<int, int>> muchie;
    std::vector<bool> used;
    std::vector<int> l;
    std::vector<int> rez;
    int start=0;
    int dest=n-1;

    for(auto i = 0; i<n ; i++){
        lista.push_back(l);
    }

    for(auto i = 0; i<m ; i++){
        used.push_back(false);
    }

    for( int i=0 ; i<m ; i++){
        f>>a>>b;
        lista[a-1].push_back(i);
        lista[b-1].push_back(i);
        muchie.push_back(std::make_pair(a-1, b-1));
    }

    s.push(0);

    while( !s.empty()){
        int nod = s.top();

        if(!lista[nod].empty()){ // apartine unei muchii
            int m_cnt = lista[nod].back();
            lista[nod].pop_back();

            if(!used[m_cnt]){ //muchia nu a fost folosita
                used[m_cnt] = true;
                int vecin;
                if(  nod == muchie[m_cnt].first) vecin = muchie[m_cnt].second;
                else vecin = muchie[m_cnt].first;
                s.push(vecin);
            }
        } else {
            s.pop();
            rez.push_back(nod);
        }
    }

    for(int i=0 ; i< rez.size() -1 ; i++)
        fg<<rez[i] + 1<< " ";

}

int graf::hamilton(int conf, int stop, std::vector<std::vector<int>> &cost, int C[262150][20]){
    if(C[conf][stop] == -1){
        C[conf][stop]  = INT_MAX/2;
        for( size_t i=0 ; i< lista[stop].size() ; i++){
            if( conf & (1<<lista[stop][i])){ // apartine lantului
                if( lista[stop][i] == 0 && conf != (1<<(stop)) + 1) continue;

                C[conf][stop] = std::min(C[conf][stop], hamilton(conf ^ (1<<stop), lista[stop][i], cost, C) + cost[lista[stop][i]][stop]); //verifica ciclu fara stop
            }
        }
    }

    return C[conf][stop];
}


// O( m * 2^n )
// Un ciclu se numeste hamiltonian daca contine fiecare nod o singura data
// Avem o structura C de tipul [configuratie][nod]
// configuratia este un numar care practic reprezinta "vectorul semafor" al nodurilor din ciclu
// semaforul acesta e reprezentat prin scrierea a i-uluia bit al numarului ca 1 daca nodul se regaseste in ciclu
// daca avem 5 numere => 11111 inseamna toate se regasesc in ciclu iar configuratia va fi numarul 31
// dinamic, parcurgem posibilitatiile si verificam minimul
// deoarece nodul de start nu conteaza ( pentru ca oricum toate nodurile sunt parcurse intr-un ciclu)
// am ales 0 ca fiind locul de pornire, simplificand programarea dinamica ls un singur nod de start

void graf::solve_hamilton() {
    std::ifstream f("hamilton.in");
    std::ofstream fg("hamilton.out");

    f>>n>>m;

    std::stack<int> s;
    std::vector<int> v;
    std::vector<int> l(n,INT_MAX/2);
    std::vector<int> lc(n,-1);
    std::vector<std::vector<int>> cost;
    int C[262150][20];
    int rez = INT_MAX;

    for(auto i = 0; i<n ; i++){
        lista.push_back(v);
        cost.push_back(l);
    }

    for( int i=0 ; i<m ; i++){
        f>>a>>b>>c;
        new_lista_orientat(b, a);
        cost[a][b] = c;
    }

    memset(C, -1, sizeof(C));
    C[1][0] = 0;

    for(size_t i = 0 ; i<lista[0].size() ; i++){
        rez = std::min( rez, hamilton((1<<n)-1, lista[0][i] , cost, C) + cost[lista[0][i]][0]);
    }

    if(rez !=INT_MAX) fg<<rez;
    else fg<<"Nu exista solutie";
}

int main() {
    graf g;

    g.solve_DFS_componente_conexe();

    return 0;
}