Cod sursa(job #2821738)

Utilizator pizzandreeaCiurescu Andreea pizzandreea Data 22 decembrie 2021 22:50:56
Problema Ciclu Eulerian Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 15.85 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>

#define MAX 100001
#define INF 0x3f3f3f3f

using namespace std;
ifstream fin ("ciclueuler.in");
ofstream fout("ciclueuler.out");



class Graf{
public:
    //date membre
    vector <int> A[MAX];    //liste de adiacenta
    vector <vector <pair<int, int>>> Ca ;      //lista de adiacenta cu costuri
    vector <pair<pair<int, int>, int> > Ac;     //vector de muchii cu costuri

    //noduri, muchii
    int mM, mN;

    //constructor

    Graf(int N, int M = 0){
        mN = N;
        mM = M;
    }


    void BFS();

    void DFS(int start, vector<bool> &viz, stack<int> &S);
    void ComponenteConexe();


    void ComponenteBiconexe();
    void DFS_Biconex(int start, int father, vector <bool> &viz, vector <int> &up, vector <int> &nivel, stack <int> &S, int & nrComp, vector<vector<int>> &compBiconexe);
    void AfisareBiconex(int nrComp, vector<vector<int>> &compBiconexe);


    void ComponenteTareConexe();
    void DFST(const vector<vector<int>> &AT, int start, int comp, vector<bool> &viz, vector<vector<int>> &compTareConexe);

    void SortareTop();
//-----------------------------  drumuri minime si APM -----------------------------
    int Find(int x, vector <int> &parent);
    void Union(int x, int y, int &msol, vector <int> &parent, vector <int> &rank);
    void APM();

    void Disjoint();

    void Dijkstra(int start);

    void Bellman(int start);

//-------------------------------------- lab 5 ---------------------------------

    void Royfloyd();

    void Diametru();
    void DFSA(int s, int dist, vector <bool> &viz, int &diametru, int &start);

//-------------------------------------- lab 6 ---------------------------------

    void Eulerian();
    void Parcurgere(int start, vector <bool> &viz, vector <int> &sol);


};


void Graf :: BFS(){

    int x, y, start;
    fin >> start;
    for(int i = 1; i <= mM; i++){
        fin >> x >> y;
        A[x].push_back(y);
    }

    bool viz[MAX] = {false};
    queue <int> Q;

    int lg[MAX] = {0};  // lungimea drumului

    // vizitam nodul curent
    viz[start] = true;
    // il punem in coada
    Q.push(start);

    // fout<<1;
    while ( !Q.empty() ){
        x = Q.front();
        Q.pop();
        // preluam primul element din coada apoi il eliminam din coada

        for(int i = 0; i < A[x].size(); i++){
            // parcurgem toti vecinii lui x
            if(viz[A[x][i]] == 0){   // daca nu am mai vizitat vecinul asta{
                Q.push(A[x][i]);

                // il vizitam
                viz[A[x][i]] = 1;
                // creste lungimea drumului
                lg[A[x][i]] = lg[x] + 1;

            }
        }
    }

    for(int i = 1; i <= mN; i++)
        if(viz[i] != 0)
            fout << lg[i] << " ";
        else
            fout << -1 << " ";

}

void Graf::DFS(int start, vector<bool> &viz, stack<int> &S) {
    viz[start] = true;
    // vizitam nodul din care plecam

    for(int i = 0; i < A[start].size(); i++){
        // parcurgem toti vecinii nodului start
        if(!viz[A[start][i]] ){
            // daca nu am mai vizitat acest vecin
            DFS(A[start][i], viz, S);
        }
    }
    S.push(start);
}


void Graf::ComponenteConexe() {
    int x, y;
    stack <int> S;

    for(int i = 1; i <= mM; i++){
        fin >> x >> y;
        A[x].push_back(y);
        A[y].push_back(x);
    }

    vector<bool> viz(mN+1, false);
    int nrComp = 0;

    for(int i = 1; i <= mN; i++){
        if(!viz[i]){
            nrComp++;
            DFS(i,viz, S);
        }
    }

    fout << nrComp;

}

void Graf::DFS_Biconex(int start, int father, vector<bool> &viz, vector<int> &up, vector<int> &nivel, stack<int> &S,
                       int &nrComp, vector<vector<int>> &compBiconexe) {
    viz[start] = true;
    // vizitam nodul din care plecam
    up[start] = nivel[start];
    S.push(start); // adaugam startul in stiva

    for ( auto i : A[start] ){
        // parcurgem toti vecinii nodului start

        if ( i == father ) continue;

        //daca nu e nodul din care am venit
        if ( viz[i] ){
            // daca am mai vizitat acest vecin
            up[start] = min(up[start], nivel[i]);
        }
        else{

            nivel[i] = nivel[start] + 1;
            DFS_Biconex(i, start, viz, up, nivel, S, nrComp,compBiconexe);

            if ( up[i] >= nivel[start] ){

                nrComp++;
                while ( !S.empty() && S.top() != i ){
                    compBiconexe[nrComp].push_back(S.top());
                    S.pop();
                }
                compBiconexe[nrComp].push_back(S.top());
                S.pop();
                compBiconexe[nrComp].push_back(start);
            }
            up[start] = min(up[start], up[i]);
        }
    }
}

void Graf::AfisareBiconex(int nrComp, vector<vector<int>> &compBiconexe) {
    fout << nrComp << "\n";
    for ( int i = 1; i <= nrComp; i++ ){
        for ( auto j : compBiconexe[i] )
            fout << j << " ";
        fout << "\n";
    }
}

void Graf::ComponenteBiconexe() {
    int x, y;
    vector <vector<int>> compBiconexe(mN+1);
//    bool viz[MAX] = {false};
    vector <bool> viz(mN+1,0);
    int nrComp = 0;
//    int up[MAX] = {0};
    vector <int> up(mN+1, 0);
//    int nivel[MAX] = {0};
    vector <int> nivel(mN+1, 0);
//    int S[MAX] = {0};
    stack <int> S;

//    int top = 0;

    for(int i = 1; i <= mM; i++){
        fin >> x >> y;
        A[x].push_back(y);
        A[y].push_back(x);
    }

    DFS_Biconex(1,0, viz, up, nivel, S, nrComp, compBiconexe);
    AfisareBiconex(nrComp, compBiconexe);
}


void Graf::DFST(const vector<vector<int>>& AT, int start, int comp, vector<bool> &viz, vector<vector<int>> &compTareConexe) {

    viz[start] = true;
    // fout << 1;
    compTareConexe[comp].push_back(start);

//    for(int i = 0; i < AT[start].size(); i++){
    for(auto x : AT[start]){
        if(!viz[x] )
            DFST(AT, x, comp, viz, compTareConexe);
    }
}

void Graf::ComponenteTareConexe() {
    vector <bool> viz(mN+1, false);

    //graful transpus
    vector<vector<int>> AT(mN + 1);

    //componente tare conexe
    vector<vector<int>> compTareConexe(mN+1);

    //stiva
    stack<int> ST;

    //nr componente tare conexe
    int nrcomp = 0;

    int x, y;

    for(int i = 1; i <= mM; i++){
        fin >> x >> y;
        A[x].push_back(y);
        AT[y].push_back(x);
    }

    for(int i = 1; i <= mN; i++){
        if(!viz[i]){
            DFS(i, viz, ST);
        }
    }

    vector<bool> vizT(mN+1, false);

    //luam elementele in ordinea inversa a parcurgerii dfs
    //si aplicam dfs pe graful transpus
    while(!ST.empty()){
        x = ST.top();
        ST.pop();

        if(!vizT[x]){
            nrcomp ++;
            DFST(AT, x, nrcomp, vizT, compTareConexe);
        }
    }

    fout << nrcomp << "\n";

    for(int i = 1; i <= nrcomp; i++){
//        for(int j = 0; j < compTareConexe[i].size(); j++){
        for(auto x : compTareConexe[i]){
            fout << x << " ";
        }
        fout << "\n";
    }
}

void Graf::SortareTop() {

    int x, y;
    vector <bool> viz(mN+1, false);
    //stiva
    stack<int> ST;

    for(int i = 1; i <= mM; i++){
        fin >> x >> y;
        A[x].push_back(y);
    }

    for(int i = 1; i <= mN; i++){
        if(!viz[i]){
            DFS(i, viz, ST);
        }
    }

    while(!ST.empty()){
        fout << ST.top() << " ";
        ST.pop();
    }
}
// conditie de sortare
bool ok(const pair<pair<int, int>, int>&x, const pair<pair<int, int>, int>&y){
    //comparam al 2 lea parametru din perechile de tipul ((x,y),c) - care reprezinta costul
    return (x.second < y.second);
}


int Graf::Find(int x, vector<int> &parent) {
    //daca nu mai gasim tata pentru nodul curent
    if( x == parent[x])
        return x;

    //mergem din tata in tata pana gasim nodul de start
    parent[x] = Find(parent[x], parent);
    return parent[x];
}

void Graf::Union(int x, int y, int &msol, vector<int> &parent, vector<int> &rank) {
    //gasim radacina/stramosul fiecarei componente pe care vrem sa le unim
    int px = Find(x, parent);
    int py = Find(y, parent);

    if(rank[px] >= rank[py]){
        //parintele subarborelui mai mic devine subarborele mare (Radacina sa)

        parent[py] = px;
        rank[px] += rank[py];
        msol++;
    }
    else{

        parent[px] = py;
        rank[py] += rank[px];
        msol++;
    }
}

void Graf::APM() {

    vector<int> parent(mN+1);
    vector<int> rank(mN+1, 1);
    for (int i = 1; i <= mN; i++)
        parent[i] = i;

    int C = 0; //costul total
    //momentan n avem nicio muchie solutie
    int msol = 0;
    //muchiile solutie
    vector <pair<int, int> > sol;

    int x,y,c;

    for(int i = 0; i < mM; i++){

        fin >> x >> y >> c;
        Ac.push_back(make_pair(make_pair(x,y),c));

    }
    //sortam vectorul de muchii crescator in fc de cost
    sort(Ac.begin(), Ac.end(), ok);

    //verificam muchiile pe rand
    for(int i = 0 ; i < mM; i++){

        //cautam "cel mai indepartat stramos" pentru ambele capete ale muchiei
        x = Find(Ac[i].first.first, parent);
        y = Find(Ac[i].first.second, parent);
        //fout << Ac[i].first.first << " tatal: " << x << "\n";
        //fout << Ac[i].first.second << " tatal: " << y << "\n";

        //daca nu au "stramos" comun, atunci nu exista alt drum de la x la y in afara de muchia x-y
        if(y != x){
            //o adaugam in vect de sol
            sol.push_back(make_pair(Ac[i].first.first, Ac[i].first.second));

            //si punem muchia pe graful nostru actual
            Union(Ac[i].first.first, Ac[i].first.second, msol, parent, rank);

            //adunam costul muchiei la costul tota
            C+= Ac[i].second;
        }
    }

    fout << C << "\n";
    fout << msol <<"\n";

    for(int i = 0; i < msol; i++){
        fout << sol[i].first << " " << sol[i].second << "\n";

    }

}

void Graf::Disjoint() {
    int x,y,op;
    vector<int> parent(mN+1);
    vector<int> rank(mN+1, 1);

    //stiu ca n am nevoie de ele dar sa nu mai scriu alta functie de union, care in final face acelasi lucru
    int msol = 0;
    //muchiile solutie
    vector <pair<int, int> > sol;


    for (int i = 1; i <= mN; i++)
        parent[i] = i;

    for(int i = 0; i < mM; i++){

        fin >> op >> x >> y;
        if(op == 1){
            Union(x,y, msol, parent, rank);
        }
        else
        if(Find(x, parent) == Find(y, parent))
            fout << "DA\n";
        else
            fout << "NU\n";
    }
}

void Graf::Dijkstra(int start) {
    //vector pt drumurile minime
    vector<int> D(mN+1, INF);
    D[start] = 0;
    //multimea nodurilor pt care inca n am calculat durmul  minim
    vector <int> F(mN+1, 0);
    Ca.resize(mN+1);
    int x,y,c;

    for(int i = 0; i < mM; i++){

        fin >> x >> y >> c;
        Ca[x].push_back(make_pair(y,c));

    }

    priority_queue <pair<int, int>>q;
    q.push(make_pair(0,start));

    while (!q.empty())
    {
        int nod = q.top().second;
        q.pop();
        if (!F[nod] ){
            F[nod] = true;
            for (auto curr : Ca[nod])
            {
                if (D[nod] + curr.second < D[curr.first])
                {
                    D[curr.first] = D[nod] + curr.second;
                    q.push(make_pair(-D[curr.first], curr.first));
                }
            }
        }
    }
    for (int i = 2; i <= mN; i++)
        if (D[i] != INF)
            fout << D[i] << " ";
        else fout << 0 << " ";

}

void Graf::Bellman(int start) {

    Ca.resize(mN+1);
    int x,y,c;
    queue <int> C;
    vector <int> D(mN+1, INF);
    vector <int> viz(mN+1, 0);
    vector <bool> incoada(mN+1, 0);

    C.push(start);
    D[start] = 0; // distanta de la un nod la el insasi e 0
    incoada[start] = 1;


    bool ciclun = 0;

    for(int i = 0; i < mM; i++){

        fin >> x >> y >> c;
        Ca[x].push_back(make_pair(y,c));

    }
    while(!C.empty() && !ciclun){
        //fout << 1;
        int nod;
        nod = C.front();
        C.pop();
        incoada[nod] = 0; //nodul nu mai e in stiva

        //parcurgem toti vecinii nodului
        for(int i = 0; i < Ca[nod].size(); i++){
            int vecin  = Ca[nod][i].first;
            int cost = Ca[nod][i].second;
            //cout << "nodul " << nod <<" si vecinul " << vecin<<"\n";

            if(D[nod] + cost < D[vecin]){
                D[vecin] = D[nod] + cost;

                if(!incoada[vecin]){
                    C.push(vecin);
                    incoada[vecin] = 1;
                }

                viz[vecin] ++;
                if(viz[vecin] >= mN){
                    ciclun = 1;
                    break;
                }
            }

        }

    }

    if(ciclun)
        fout << "Ciclu negativ!";
    else{
        for(int i = 2; i <= mN; i++)
            fout << D[i] << " ";

    }


}

void Graf::Royfloyd() {
    //matrice de adiacenta cu costuri
    vector<vector<int> > M(mN+1);

    for(int i = 1; i <= mN; i++){
        M[i].resize(mN+1, 0);
    }

    for(int i = 1; i <= mN; i++){
        for(int j =1; j <= mN; j++){
            fin >> M[i][j];
            if(!M[i][j] && i != j){
                M[i][j] = INF;
            }
        }
    }

    int i,j,k;

    for(int k = 1; k <= mN; k++){
        for(int i = 1; i <= mN; i++){
            for(int j = 1; j <= mN; j++){
                M[i][j] = min(M[i][j], M[i][k] + M[k][j]);
            }
        }
    }


    for(int i = 1; i <= mN; i++){
        for(int j = 1; j <= mN; j++){
            if(M[i][j] != INF){
                fout << M[i][j] <<" ";
            }
            else
                fout << 0 << " ";
        }
        fout << "\n";
    }


}

void Graf::DFSA(int s, int dist, vector<bool> &viz, int &diametru, int &start) {
    viz[s] = true;

    if(dist > diametru){
        diametru = dist;
        start = s;

    }

    for(int i = 0; i < A[s].size(); i++){
        if(!viz[A[s][i]])
            DFSA(A[s][i], dist+1, viz, diametru, start);
    }
}

void Graf::Diametru() {
    int x,y;

    vector <bool> viz(mN+1, false);

    for(int i = 1; i < mN; i++){
        fin >> x >> y;
        A[x].push_back(y);
        A[y].push_back(x);
    }

    int diametru = 0;
    int start = 1;
    DFSA(1, 0, viz, diametru, start);

    for(int i = 1; i <= mN; i++)
        viz[i] = false;



    DFSA(start, 0, viz, diametru, start);
    fout << diametru + 1;

}


void Graf::Parcurgere(int start, vector<bool> &viz, vector<int> &sol) {
    stack <int> S;
    S.push(start);

    while(!S.empty()){
        int nod = S.top();
        //daca nodul mai are vecini
        if(!Ca[nod].empty()){
            //luam ultimul vecini din lista de adiacenta a nodului curent
            //si indicele muchiei formate
            int urm = Ca[nod][Ca[nod].size()-1].first;
            int ind = Ca[nod][Ca[nod].size()-1].second;

            //si eliminam muchia
            Ca[nod].pop_back();

            if(viz[ind] == 0){
                //marcam muchia ca si vizitata
                viz[ind] = true;
//                punem nodul in coada pentru ai vizita si muchiile lui
                S.push(urm);
            }
        }
        else{
            // daca i am vizitat toate muchiile care au un capat in nod
            sol.push_back(nod);
            S.pop();
        }
    }
}

void Graf::Eulerian() {
    int x, y;
    //vector viz pt muchii
    vector <bool> viz(mM + 1, false);
    vector <int> sol;
    Ca.resize(mN+1);

    for(int i = 0; i < mM; i++){
        //pentru fiecare muchie retinem si indicele ei
        fin >> x >> y ;
        Ca[x].push_back(make_pair(y,i));
        Ca[y].push_back(make_pair(x,i));

    }

    //veridicam daca exista noduri cu grad impar
    for(int i = 0; i <= mN; i++){
        if(Ca[i].size() % 2 == 1){
            fout << -1;
            return ;
        }
    }

    Parcurgere(1, viz, sol);

    for(int i = 0; i < sol.size(); i++){
        fout << sol[i] << " ";
    }


}



int main(){
    int N, M;
    fin >> N >> M;
    // fout << 1;
    Graf G(N, M);
    G.Eulerian();


    return 0;
}