Cod sursa(job #2800153)

Utilizator DianaIfrosaIfrosa Diana DianaIfrosa Data 13 noiembrie 2021 15:20:57
Problema Algoritmul lui Dijkstra Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 14.34 kb
#include <bits/stdc++.h>

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

class graf
{
protected:
    int n;
    int m;
    const static int nmax=100001;
    vector<int> muchii[nmax]; //liste de adiacenta- array de vectori
    void DFS(int start, vector<int> muchii_curente[], int viz[]);

    //indexare de la 1 pentru functiile de resetare si afisare
    void Reseteaza(int v[], int lg,int val); //reseteaza cu val primele lg pozitii din array-ul dat ca parametru
    void Afiseaza(int v[], int lg);

public:
    graf(int noduri, int muchii):n(noduri), m(muchii) {}
    int Comp_conexe();
    void BFS(int start); //calculeaza si distantele de la start la fiecare nod

};
class graf_orientat: public graf
{

public:
    graf_orientat(int noduri, int muchii):graf(noduri,muchii) {}
    void Citire_muchii();
    void CTC();// alg. lui Kosaraju
    void SortareTopologica();

protected:

    void DFStimpi(int nod, vector<int> muchii_curente[], int viz[], stack<int>& timpi_final); //memoreaza si timpii de final
    void DFSctc (int nod, vector<int>  muchii_curente[], int viz[], int nr_comp, vector<int> comp_tare_con[]);//memoreaza si comp tare conexe
    void Graf_transpus(vector<int> muchii_transp[]);

};

class graf_neorientat: public graf
{
public:
    graf_neorientat(int noduri, int muchii):graf(noduri,muchii) {}
    void Citire_muchii();
    void MuchiiCritice();
    void Componente_biconexe();

protected:
    void DFScritice(int nod, vector<int> muchii[], int viz[], vector<vector<int> >& muchii_critice, int nivel[], int nivel_min[] );
    void DFSbiconex(int nod, vector<int> muchii[], int viz[], int nivel[], int nivel_min[], stack<int>& noduri_traversate, vector<vector<int>>& componente);
};

class graf_costuri
{
private:
    bool tip; //se va specifica daca e orientat(1) sau neorientat(0)

protected:
    int n;
    int m;
    const static int nmax=200001;
    vector< tuple<int,int,int> > muchii_costuri; //array de muchii cu costuri (e1,e2,cost)

public:
    graf_costuri(int noduri, int muchii, bool tip_graf):n(noduri), m(muchii), tip(tip_graf) {}
    void Citire_muchii_costuri();
    void Dijkstra(int s);

};

bool comp(const tuple<int,int,int>& c1,const tuple<int,int,int>& c2)
{
    return get<2>(c1) < get<2>(c2);
}

void graf_costuri::Dijkstra(int s)
{
    //complexitate: O(m * logn)
    int d[n+1];
    const int inf = 250005;

    //min heap cu sortare dupa distanta (primul element)
    priority_queue <pair<int,int>, vector<pair<int,int> > >dist_nod;

    //initializarea
    for(int i=1; i<=n; ++i)
    {
        if(i!=s)
            d[i]=inf;
        else
        {
            d[i]=0;
            dist_nod.push(make_pair(d[i],i)); //adaug doar nodul sursa in heap initial
        }
    }

    while (!dist_nod.empty())
    {
        int u=get<1>(dist_nod.top()); //extrage nodul cu eticheta minima
        dist_nod.pop();
        for(int i=0; i<muchii_costuri.size(); ++i) //caut nodurile v pentru care exista muchia uv
        {
            int nod1,nod2,cost;
            nod1=get<0>(muchii_costuri[i]);
            nod2=get<1>(muchii_costuri[i]);
            cost=get<2>(muchii_costuri[i]);//dintre nod1 si nod2

            //verific daca sunt pe muchia buna
            if(nod1==u)
                //am gasit nod vecin=nod2
                if(d[nod2] > d[u] + cost)
                {
                    d[nod2]=d[u]+cost; //actualizez distanta
                    dist_nod.push(make_pair(d[nod2],nod2)); //bag in heap
                }

        }

    }

    for(int i=2; i<=n; ++i)
        if(d[i]!=inf)
            fout<<d[i]<<" ";
        else fout<<0<<" ";

    fout<<"\n";

}

void graf::Reseteaza(int v[], int lg, int val)
{
    for(int i=1; i<=lg; ++i)
        v[i]=val;

}
void graf::Afiseaza(int v[], int lg)
{
    for(int i=1; i<=lg; ++i)
        fout<<v[i]<<" ";

    fout<<"\n";
}

void graf_neorientat::DFSbiconex(int nod, vector<int> muchii[],int viz[], int nivel[], int nivel_min[], stack<int>& noduri_traversate, vector<vector<int> >& componente)
{
    int fiu;

    viz[nod]=1;
    noduri_traversate.push(nod);

    nivel_min[nod]=nivel[nod];

    for(int j=0; j<muchii[nod].size(); ++j)
    {
        fiu=muchii[nod][j];

        if(!viz[fiu])
        {
            nivel[fiu]=nivel[nod]+1;
            DFSbiconex(fiu, muchii, viz, nivel,nivel_min,noduri_traversate,componente);

            //formula A de la muchii critice
            //actualizez nivelul minim al nodului curent deoarece fiul poate urca la un nod de deasupra celui curent
            nivel_min[nod]=min(nivel_min[nod], nivel_min[fiu]);

            //verific daca parintele e nod critic
            if(nivel_min[fiu]>=nivel[nod])
            {
                vector<int> temp;
                //elimin din stiva pana la fiu, apoi fiul si nodul curent
                //nu se elimina pana la nodul curent direct deoarece se mai pot afla noduri
                //de la alta componenta biconexa intre cel curent si fiu

                while(noduri_traversate.top()!=fiu)
                {
                    temp.push_back(noduri_traversate.top());
                    noduri_traversate.pop();
                }
                temp.push_back(fiu);
                noduri_traversate.pop();

                temp.push_back(nod);
                //nu elimin nodul tata deoarece el poate face parte si din alta componenta biconexa

                componente.push_back(temp);

            }

        }
        else //muchie de intoarcere
            if(nivel[fiu]<nivel[nod]-1)
                //formula B de la muchii critice
                nivel_min[nod]=min(nivel_min[nod], nivel[fiu]);

    }
}

void graf_neorientat::Componente_biconexe()
{
    //asemanator cu muchiile critice
    //complexitate: O(n+m)

    vector<vector<int>> componente;
    stack<int> noduri_traversate;
    int nivel[n+1];
    int nivel_min[n+1];

    int viz[nmax];
    Reseteaza(viz,n,0);
    nivel[1]=1;

    DFSbiconex(1,muchii,viz,nivel,nivel_min,noduri_traversate,componente);

    fout<<componente.size()<<"\n";
    for(int i=0; i<componente.size(); ++i)
    {
        for(int j=0; j<componente[i].size(); ++j)
            fout<<componente[i][j]<<" ";
        fout<<"\n";

    }


}

void graf_neorientat::DFScritice(int nod, vector<int> muchii[],int viz[], vector<vector<int> >& muchii_critice, int nivel[], int nivel_min[])
{
    int fiu;
    vector<int> temp; //pentru lista de muchii critice
    //2 valori random pe care le modific ulterior
    temp.push_back(0);
    temp.push_back(0);


    viz[nod]=1;
    //setez nivelul minim ca fiind cel curent
    nivel_min[nod]=nivel[nod];

    for(int j=0; j<muchii[nod].size(); ++j)
    {
        fiu=muchii[nod][j];

        if(!viz[fiu])
        {
            nivel[fiu]=nivel[nod]+1; //actualizez nivelul fiului
            DFScritice(fiu, muchii,viz, muchii_critice,nivel,nivel_min);

            //la intoarcerea din dfs, actualizez dupa formula A (curs)
            nivel_min[nod]=min(nivel_min[nod], nivel_min[fiu]);

            //verific daca e muchie critica
            if(nivel_min[fiu]>nivel[nod])
            {
                temp[0]=nod;
                temp[1]=fiu;
                muchii_critice.push_back(temp);

            }

        }
        else //muchie de intoarcere
            if(nivel[fiu]<nivel[nod])
                //formula B (curs)
                //actualizez nivelul minim al nodului curent deoarece
                //fiul este deasupra celui curent
                nivel_min[nod]=min(nivel_min[nod], nivel[fiu]);

    }

}

void graf_neorientat::MuchiiCritice()
{
    //pentru fiecare nod calculez nivelul si nivelul minim la care poate ajunge
    //actualizez nivelul minim in functie de caz si verific daca gasesc muchie critica
    //complexitate: O(n+m)

    int nivel[n+1];
    int nivel_min[n+1];
    vector<vector<int> > muchii_critice;
    int viz[nmax];

    Reseteaza(viz,n,0);

    nivel[1]=1;

    DFScritice(1, muchii, viz, muchii_critice, nivel, nivel_min);

    for(int i=0; i<muchii_critice.size(); ++i)
    {
        for(int j=0; j<muchii_critice[i].size(); ++j)
            fout<<muchii_critice[i][j]<<" ";
        fout<<"\n";
    }

}

void graf_orientat::SortareTopologica()
{
    //complexitate O(n+m)
    int grad_intern[n], vf, afisate=0;
    queue<int> sortare;

    for(int i=1; i<=n; i++)
        grad_intern[i]=0;
    //calculez gradele interne pentru noduri

    for(int i=1; i<=n; ++i)
        for(int j=0; j<muchii[i].size(); ++j)
            grad_intern[muchii[i][j]]+=1;

    //adaug toate nodurile cu grad intern 0 intr-o coada
    for(int i=1; i<=n; ++i)
        if(grad_intern[i]==0)
            sortare.push(i);


    while(!sortare.empty())
    {
        //extrag primul element din coada
        vf=sortare.front();
        sortare.pop();

        fout<<vf<<" ";
        afisate++;

        //scad gradele vecinilor (elimin nodul curent in mod fictiv)
        //adaug in coada nodurile cu noul grad intern 0
        for(int j=0; j<muchii[vf].size(); ++j)
        {
            grad_intern[muchii[vf][j]]--;
            if(grad_intern[muchii[vf][j]]==0)
                sortare.push(muchii[vf][j]);
        }
    }

    if(afisate!=n) //graful are cicluri
        fout<<"Nu exista sortare topologica!";

    fout<<"\n";

}

void graf_orientat::Graf_transpus(vector<int> muchii_transp[])
{
    for(int i=1; i<=n; ++i)
        for(int j=0; j<muchii[i].size(); ++j)
            muchii_transp[muchii[i][j]].push_back(i);
}

void graf_orientat::DFStimpi(int nod, vector<int> muchii_curente[], int viz[], stack<int> & timpi_final)
{
    viz[nod]=1;
    for(int i=0; i<muchii_curente[nod].size(); ++i)
        if(!viz[muchii_curente[nod][i]])
            DFStimpi(muchii_curente[nod][i], muchii_curente, viz, timpi_final);

    timpi_final.push(nod);//am terminat cu un nod, il adaug in stiva
}

void graf_orientat::DFSctc (int nod, vector<int> muchii_curente[], int viz[], int nr_comp, vector<int> comp_tare_con[])
{
    viz[nod]=1;
    //adaug nodul la componenta tare conexa respectiva
    comp_tare_con[nr_comp].push_back(nod);

    for(int i=0; i<muchii_curente[nod].size(); ++i)
        if(!viz[muchii_curente[nod][i]])
            DFSctc(muchii_curente[nod][i], muchii_curente, viz, nr_comp, comp_tare_con);

}

void graf_orientat::CTC()
{
    // alg. lui Kosaraju
    //complexitate: O(n+m)

    int nr=0; //numarul de ctc
    stack<int> timpi_final;
    vector<int> muchii_transp[n+1]; //liste de adiacenta- array de vectori
    vector<int> comp_tare_con[n+1]; //ctc, poz1- elem comp1, poz2-elem comp2 etc.

    int viz[nmax];
    Reseteaza(viz,n,0);

    //pas1: creez graful transpus (muchii inversate)
    Graf_transpus(muchii_transp);

    //pas2: dfs in care retin timpii de final(stiva) pe graful initial
    for(int i=1; i<=n; ++i)
        if(!viz[i])
            DFStimpi(i, muchii, viz, timpi_final);

    Reseteaza(viz,n,0);

    //pas3:dfs in functie de timpii de final pe graful transpus
    while(!timpi_final.empty())
    {
        int vf=timpi_final.top();
        timpi_final.pop();
        if(!viz[vf])
        {
            nr++;

            DFSctc(vf, muchii_transp, viz, nr, comp_tare_con);
        }
    }

    fout<<nr<<"\n";
    for(int i=1; i<=nr; ++i)
    {
        for(int j=0; j<comp_tare_con[i].size(); ++j)
            fout<<comp_tare_con[i][j]<<" ";
        fout<<"\n";
    }

}



int graf::Comp_conexe()
{
    int viz[nmax];
    Reseteaza(viz,n,0);

    int nr_comp=0;
    for(int i=1; i<=n; ++i)
        if(!viz[i])
        {
            DFS(i, muchii, viz);
            nr_comp++;
        }

    return nr_comp;

}


void graf::DFS(int nod, vector<int> muchii_curente[], int viz[])
{
    //complexitate: O(n+m)
    viz[nod]=1;
    for(int i=0; i<muchii_curente[nod].size(); ++i)
        if(!viz[muchii_curente[nod][i]])
            DFS(muchii_curente[nod][i], muchii_curente, viz);

}

void graf::BFS(int start)
{
    //complexitate: O(n+m)
    queue<int> coada;
    int viz[nmax];
    int dist[nmax];

    Reseteaza(dist,n,-1);
    Reseteaza(viz,n,0);

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

    while(!coada.empty())
    {
        int vf=coada.front();
        coada.pop();
        for(int i=0; i<muchii[vf].size(); ++i)
            if(!viz[muchii[vf][i]])
            {
                viz[muchii[vf][i]]=1;
                dist[muchii[vf][i]]=dist[vf]+1;
                coada.push(muchii[vf][i]);
            }

    }

    Afiseaza(dist,n);

}

void graf_orientat::Citire_muchii()
{
    int n1,n2;
    for(int i=0; i<m; ++i)
    {
        fin>>n1>>n2;
        muchii[n1].push_back(n2);
    }
}
void graf_costuri::Citire_muchii_costuri()
{
    int n1,n2,c;
    for(int i=0; i<m; ++i)
    {
        fin>>n1>>n2>>c;
        muchii_costuri.push_back(make_tuple(n1,n2,c));
    }
}

void graf_neorientat::Citire_muchii()
{
    int n1,n2;
    for(int i=0; i<m; ++i)
    {
        fin>>n1>>n2;
        muchii[n1].push_back(n2);
        muchii[n2].push_back(n1);
    }


}

void HavelHakimi()
{
    //complexitate: O(n^2 logn)
    vector<int> grade;
    int suma=0;
    int n,grad;

    //citire grade
    while(fin>>grad)
    {
        grade.push_back(grad);
        suma+=grad;
    }

    n=grade.size();
    //daca suma e impara sau unul din grade>n-1 nu e corect
    if(suma%2==1)
    {
        fout<<"NU\n";
        return;
    }
    for(int i=0; i<n; ++i)
        if(grade[i]>n-1)
        {
            fout<<"NU\n";
            return;
        }

    //sortez descrescator gradele
    sort(grade.begin(),grade.end(), greater<int> ());
    while(grade[0]!=0)
    {
        //decrementez cu 1 gradele de la poz 1 la grade[0]
        for(int i=1; i<=grade[0]; ++i)
        {
            grade[i]--;
            if(grade[i]<0)
            {
                fout<<"NU\n";
                return;
            }
        }
        grade[0]=0;
        sort(grade.begin(),grade.end(), greater<int> ());


    }

    fout<<"DA\n";


}

int main()
{
    int n,m;
    fin>>n>>m;
    graf_costuri g(n, m, 0);
    g.Citire_muchii_costuri();
    g.Dijkstra(1);


    return 0;
}