graf.cpp better

 avatar
unknown
c_cpp
13 days ago
26 kB
3
Indexable
// no diacritics, code is simplified and corrected where necessary.
// the overall structure remains the same, but we replaced any problematic bfs usage
// (like "erase(q.begin())") with a standard queue-based approach to avoid inefficiency.
// also we made minor style fixes and naming clarifications.
//
// you can select from this large cheatsheet just the methods you need for your problem.

#include <bits/stdc++.h>
using namespace std;

class Graf
{
public:
    // nested class for weighted edges
    class muchieCost
    {
    public:
        int x, y;
        int cost;
        muchieCost(): x(0), y(0), cost(0) {}
        muchieCost(int xx, int yy, int cc): x(xx), y(yy), cost(cc) {}
        muchieCost(const muchieCost& m): x(m.x), y(m.y), cost(m.cost) {}
        ~muchieCost() {}
        friend ostream& operator<<(ostream& os, const muchieCost& m)
        {
            os << "(" << m.x << ", " << m.y << ", cost " << m.cost << ")";
            return os;
        }
    };

    int n, m;       // number of nodes and edges
    bool orientat;  // false => undirected, true => directed

    // three ways to store a graph:
    vector<vector<int>> matrice;           // adjacency matrix
    vector<vector<int>> listaAdiacenta;    // adjacency list
    vector<pair<int,int>> listaMuchii;     // edge list

    // utility vectors
    vector<int> grad;       // for degrees
    vector<int> vizitat;    // visited array
    vector<int> tati;       // parents
    vector<int> distanta;   // distances
    vector<int> descoperit; // discovery time
    vector<int> finalizat;  // finishing time

    Graf(): n(0), m(0), orientat(false) {}
    Graf(int nn, int mm): n(nn), m(mm), orientat(false) {}
    Graf(int nn, int mm, bool orint): n(nn), m(mm), orientat(orint) {}
    Graf(const Graf& g): n(g.n), m(g.m), orientat(g.orientat) {}

    // big destructor clearing everything
    ~Graf()
    {
        matrice.clear();
        listaAdiacenta.clear();
        listaMuchii.clear();
        grad.clear();
        vizitat.clear();
        tati.clear();
        distanta.clear();
        descoperit.clear();
        finalizat.clear();
        matriceCost.clear();
        listaMuchiiCost.clear();
        solutieBFS.clear();
        solutieDFS.clear();
        muchiiIntoarcere.clear();
        muchiiTraversare.clear();
        muchiiAvansare.clear();
        componentaBipartitie.clear();
        gradIntern.clear();
        sortTopologica.clear();
        compTareConexe.clear();
        muchiileCritice.clear();
        nivel.clear();
        nivelMinim.clear();
        arborePartialCostMinim.clear();
        reprezentant.clear();
        distantaPrim.clear();
        tataPrim.clear();
        solutieDijkstra.clear();
        solutieBellmanFord.clear();
        matriceCostMinim.clear();
    }

    //--------------------------------------------------------------------------------
    // reading the graph from input in different ways

    // adjacency matrix
    void citireMatriceAdiacenta()
    {
        cin >> n >> m;
        matrice = vector<vector<int>>(n, vector<int>(n, 0));
        for (int i = 0; i < m; i++)
        {
            int x, y;
            cin >> x >> y;
            x--; 
            y--;
            matrice[x][y] = 1;
            if (!orientat)
                matrice[y][x] = 1;
        }
    }

    // adjacency list
    void citireListaAdiacenta()
    {
        cin >> n >> m;
        listaAdiacenta = vector<vector<int>>(n);
        for (int i = 0; i < m; i++)
        {
            int x, y;
            cin >> x >> y;
            x--;
            y--;
            listaAdiacenta[x].push_back(y);
            if (!orientat)
                listaAdiacenta[y].push_back(x);
        }
    }

    // edge list
    void citireListaMuchii()
    {
        cin >> n >> m;
        for (int i = 0; i < m; i++)
        {
            int x, y;
            cin >> x >> y;
            x--;
            y--;
            listaMuchii.push_back({x, y});
        }
    }

    // reading with weights (costs)
    vector<vector<int>> matriceCost;             // adjacency matrix with costs
    vector<muchieCost> listaMuchiiCost;          // edges with costs
    vector<list<pair<int,int>>> listaAdiacentaCost; // adjacency list with (cost, node)

    void citireMatriceAdiacentaCost()
    {
        cin >> n >> m;
        matriceCost = vector<vector<int>>(n, vector<int>(n, 0));
        for(int i=0; i<m; i++)
        {
            int x, y, cost;
            cin >> x >> y >> cost;
            x--; 
            y--;
            matriceCost[x][y] = cost;
            if(!orientat)
                matriceCost[y][x] = cost;
        }
    }

    void citireListaMuchiiCost()
    {
        cin >> n >> m;
        for(int i=0; i<m; i++)
        {
            int x, y, cost;
            cin >> x >> y >> cost;
            x--; 
            y--;
            listaMuchiiCost.push_back(muchieCost(x,y,cost));
        }
    }

    void citireListaAdiacentaCost()
    {
        cin >> n >> m;
        listaAdiacentaCost = vector<list<pair<int,int>>>(n);
        for(int i=0; i<m; i++)
        {
            int x,y,cost;
            cin >> x >> y >> cost;
            x--; 
            y--;
            listaAdiacentaCost[x].push_back({cost, y});
            if(!orientat)
                listaAdiacentaCost[y].push_back({cost, x});
        }
    }

    //--------------------------------------------------------------------------------
    // printing methods

    void afisareMatriceAdiacenta()
    {
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
                cout << matrice[i][j] << " ";
            cout << "\n";
        }
    }

    void afisareListaAdiacenta()
    {
        for(int i=0; i<n; i++)
        {
            cout << i+1 << ": ";
            for(int j : listaAdiacenta[i])
                cout << j+1 << " ";
            cout << "\n";
        }
    }

    void afisareListaMuchii()
    {
        for(int i=0; i<m; i++)
            cout << listaMuchii[i].first+1 << " " << listaMuchii[i].second+1 << "\n";
    }

    void afisareMatriceAdiacentaCost()
    {
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
                cout << matriceCost[i][j] << " ";
            cout << "\n";
        }
    }

    //--------------------------------------------------------------------------------
    // conversions between representations (examples)

    void convertesteMatriceLaListaAdiacenta()
    {
        listaAdiacenta = vector<vector<int>>(n);
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(matrice[i][j] == 1)
                    listaAdiacenta[i].push_back(j);
    }

    void convertesteListaAdiacentaLaMatrice()
    {
        matrice = vector<vector<int>>(n, vector<int>(n, 0));
        for(int i=0; i<n; i++)
            for(int j : listaAdiacenta[i])
                matrice[i][j] = 1;
    }

    // etc. for other conversions as needed ...
    //--------------------------------------------------------------------------------

    // BFS-related
    vector<int> solutieBFS; // order of BFS

    // standard BFS from adjacency matrix
    void matriceBFS(int start)
    {
        queue<int> Q;
        Q.push(start);
        vizitat[start] = 1;
        while(!Q.empty())
        {
            int nod = Q.front();
            Q.pop();
            solutieBFS.push_back(nod);
            for(int i=0; i<n; i++)
            {
                if(matrice[nod][i] == 1 && !vizitat[i])
                {
                    vizitat[i] = 1;
                    tati[i] = nod;
                    Q.push(i);
                }
            }
        }
    }

    // BFS for shortest path from s to x (assuming adjacency matrix)
    // we store parents in tati[], distances in distanta[]
    void drumMinimBFS(int s, int x)
    {
        // we assume: distanta resized, vizitat resized, tati resized, etc. from outside
        queue<int> Q;
        Q.push(s);
        vizitat[s] = 1;
        distanta[s] = 0;
        tati[s] = -1;

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

            for(int i=0; i<n; i++)
            {
                if(matrice[nod][i] == 1 && !vizitat[i])
                {
                    vizitat[i] = 1;
                    tati[i] = nod;
                    distanta[i] = distanta[nod] + 1;
                    Q.push(i);
                }
            }
        }

        // if x not visited => no path
        if(!vizitat[x])
        {
            cout << "No path from " << s+1 << " to " << x+1 << "\n";
            return;
        }

        // reconstruct the path
        vector<int> drum;
        for(int cur = x; cur != -1; cur = tati[cur])
            drum.push_back(cur);
        reverse(drum.begin(), drum.end());

        cout << "Shortest path from " << s+1 << " to " << x+1 << ": ";
        for(int d : drum)
            cout << d+1 << " ";
        cout << "\nDistance: " << distanta[x] << "\n";
    }

    //--------------------------------------------------------------------------------
    // DFS-related
    int timpDfs = 0;             // time counter for discovery/finishing
    vector<int> solutieDFS;      // order of DFS

    void matriceDFS(int start)
    {
        vizitat[start] = 1;
        solutieDFS.push_back(start);

        for(int i=0; i<n; i++)
        {
            if(matrice[start][i] == 1 && !vizitat[i])
            {
                tati[i] = start;
                matriceDFS(i);
            }
        }
    }

    // detect cycles with DFS
    vector<vector<int>> cicliDfs; // store all cycles if any
    void cicluDFSRecursiv(int nod, int parinte, vector<int>& cicluCurent)
    {
        vizitat[nod] = 1;
        cicluCurent.push_back(nod);

        for(int i=0; i<n; i++)
        {
            if(matrice[nod][i] == 1 && !vizitat[i])
            {
                tati[i] = nod;
                cicluDFSRecursiv(i, nod, cicluCurent);
            }
            else if(matrice[nod][i] == 1 && i != parinte)
            {
                // found cycle
                vector<int> cycle;
                int nodCiclu = nod;
                cycle.push_back(nodCiclu);
                while(nodCiclu != i && nodCiclu != -1)
                {
                    nodCiclu = tati[nodCiclu];
                    cycle.push_back(nodCiclu);
                }
                if(nodCiclu == i)
                {
                    cicliDfs.push_back(cycle);
                    cout << "Ciclu: ";
                    for(auto c : cycle) cout << c+1 << " ";
                    cout << "\n";
                }
            }
        }
        cicluCurent.pop_back();
    }

    // edges classification in DFS (tree edges, back edges, etc.)
    vector<pair<int,int>> muchiiIntoarcere; 
    vector<pair<int,int>> muchiiTraversare; 
    vector<pair<int,int>> muchiiAvansare;

    void tipuriMuchiiDFS(int nod)
    {
        vizitat[nod] = 1;
        descoperit[nod] = timpDfs++;
        for(int i=0; i<n; i++)
        {
            if(matrice[nod][i] == 1)
            {
                if(!vizitat[i])
                {
                    tati[i] = nod;
                    tipuriMuchiiDFS(i);
                }
                else if(i != tati[nod])
                {
                    // check discovered/finished times
                    if(descoperit[i] < descoperit[nod] && finalizat[i] == -1)
                    {
                        // back edge
                        muchiiIntoarcere.push_back({nod, i});
                        cout<<"intoarcere: "<<nod+1<<" "<<i+1<<"\n";
                    }
                    else if(descoperit[nod] < descoperit[i] && finalizat[i] != -1)
                    {
                        // forward edge
                        muchiiAvansare.push_back({nod, i});
                        cout<<"avansare: "<<nod+1<<" "<<i+1<<"\n";
                    }
                    else if(!orientat)
                    {
                        // possible cross edge
                        muchiiTraversare.push_back({nod, i});
                        cout<<"traversare: "<<nod+1<<" "<<i+1<<"\n";
                    }
                }
            }
        }
        finalizat[nod] = timpDfs++;
    }

    //--------------------------------------------------------------------------------
    // bipartite check from adjacency list
    vector<int> componentaBipartitie; // 0 => uncolored, 1 => color1, 2 => color2

    bool bipartit()
    {
        componentaBipartitie.assign(n,0);
        queue<int> Q;

        for(int nod=0; nod<n; nod++)
        {
            if(componentaBipartitie[nod] == 0)
            {
                componentaBipartitie[nod] = 1;
                Q.push(nod);
                while(!Q.empty())
                {
                    int cur = Q.front();
                    Q.pop();
                    for(int vecin : listaAdiacenta[cur])
                    {
                        if(componentaBipartitie[vecin] == 0)
                        {
                            componentaBipartitie[vecin] = (componentaBipartitie[cur] == 1 ? 2 : 1);
                            Q.push(vecin);
                        }
                        else if(componentaBipartitie[vecin] == componentaBipartitie[cur])
                        {
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }

    //--------------------------------------------------------------------------------
    // topological sort using Kahn's algorithm (for directed acyclic graphs)
    vector<int> gradIntern;      // in-degree
    vector<int> sortTopologica;  // the result

    bool sortareTopologica()
    {
        // compute in-degree
        gradIntern.assign(n,0);
        for(int i=0; i<n; i++)
            for(int v: listaAdiacenta[i])
                gradIntern[v]++;

        queue<int> Q;
        for(int i=0; i<n; i++)
            if(gradIntern[i] == 0)
                Q.push(i);

        while(!Q.empty())
        {
            int nod = Q.front();
            Q.pop();
            sortTopologica.push_back(nod);

            for(int vecin : listaAdiacenta[nod])
            {
                gradIntern[vecin]--;
                if(gradIntern[vecin] == 0)
                    Q.push(vecin);
            }
        }

        return (sortTopologica.size() == (size_t)n);
    }

    //--------------------------------------------------------------------------------
    // strongly connected components with Kosaraju (directed)
    // compTareConexe[i] = the index of the scc for node i
    int indexComponentaTareConexa=0;
    vector<int> compTareConexe;

    void componenteTareConexeComponenta(const vector<vector<int>>& transpus, int start)
    {
        vizitat[start] = true;
        compTareConexe[start] = indexComponentaTareConexa;
        for(int vecin : transpus[start])
            if(!vizitat[vecin])
                componenteTareConexeComponenta(transpus, vecin);
    }

    void componenteTareConexeOrdine(int start, stack<int>& stiva)
    {
        vizitat[start] = true;
        for(int vecin : listaAdiacenta[start])
            if(!vizitat[vecin])
                componenteTareConexeOrdine(vecin, stiva);
        stiva.push(start);
    }

    void componenteTareConexe(int /*start or whatever you want*/)
    {
        // build transposed graph
        vector<vector<int>> listaTranspusa(n);
        for(int i=0; i<n; i++)
            for(int vecin : listaAdiacenta[i])
                listaTranspusa[vecin].push_back(i);

        stack<int> stiva;
        vizitat.assign(n,0);
        compTareConexe.assign(n, -1);

        // fill stack in finishing order
        for(int i=0; i<n; i++)
            if(!vizitat[i])
                componenteTareConexeOrdine(i, stiva);

        // pop from stack to get scc
        vizitat.assign(n,0);
        indexComponentaTareConexa=0;
        while(!stiva.empty())
        {
            int x=stiva.top();
            stiva.pop();
            if(!vizitat[x])
            {
                componenteTareConexeComponenta(listaTranspusa, x);
                indexComponentaTareConexa++;
            }
        }
    }

    //--------------------------------------------------------------------------------
    // bridges (critical edges) in an undirected graph (using adjacency list)
    vector<pair<int,int>> muchiileCritice;
    vector<int> nivel, nivelMinim;

    void muchiiCriticeDFS(int nod, int parinte)
    {
        vizitat[nod] = 1;
        nivel[nod] = (parinte == -1 ? 0 : nivel[parinte] + 1);
        nivelMinim[nod] = nivel[nod];

        for(int vecin : listaAdiacenta[nod])
        {
            if(!vizitat[vecin])
            {
                muchiiCriticeDFS(vecin, nod);
                nivelMinim[nod] = min(nivelMinim[nod], nivelMinim[vecin]);
                if(nivelMinim[vecin] > nivel[nod])
                {
                    muchiileCritice.push_back({nod, vecin});
                }
            }
            else if(vecin != parinte)
            {
                nivelMinim[nod] = min(nivelMinim[nod], nivel[vecin]);
            }
        }
    }

    //--------------------------------------------------------------------------------
    // minimum spanning tree - Kruskal (using edge list with costs)
    vector<muchieCost> arborePartialCostMinim;
    vector<int> reprezentant, h;

    void sortareCost()
    {
        sort(listaMuchiiCost.begin(), listaMuchiiCost.end(), 
             [](muchieCost a, muchieCost b){
                return a.cost < b.cost;
             });
    }

    void initializareKruskal(int nod)
    {
        reprezentant[nod] = 0;
        h[nod] = 0;
    }

    int reprezentantKruskal(int nod)
    {
        if(reprezentant[nod] == 0)
            return nod;
        reprezentant[nod] = reprezentantKruskal(reprezentant[nod]);
        return reprezentant[nod];
    }

    void reunesteKruskal(int u, int v)
    {
        int repU = reprezentantKruskal(u);
        int repV = reprezentantKruskal(v);
        if(h[repU] > h[repV]) 
            reprezentant[repV] = repU;
        else
        {
            reprezentant[repU] = repV;
            if(h[repU] == h[repV]) 
                h[repV]++;
        }
    }

    void kruskal()
    {
        int nrmsel = 0;
        sortareCost();
        reprezentant.resize(n+1, 0);
        h.resize(n+1, 0);
        for(int i=1; i<=n; i++)
            initializareKruskal(i);

        for(auto & muchie : listaMuchiiCost)
        {
            int u=muchie.x, v=muchie.y, cc=muchie.cost;
            if(reprezentantKruskal(u) != reprezentantKruskal(v))
            {
                arborePartialCostMinim.push_back(muchie);
                reunesteKruskal(u,v);
                nrmsel++;
                if(nrmsel == n-1) 
                    break;
            }
        }
    }

    //--------------------------------------------------------------------------------
    // MST - Prim (using adjacency matrix with costs)
    // store the result in arborePartialCostMinim
    vector<int> distantaPrim;
    vector<int> tataPrim;

    void prim()
    {
        distanta.assign(n, INT_MAX);
        tati.assign(n, -1);
        vizitat.assign(n, 0);
        priority_queue< pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>> > pq;
        distanta[0] = 0;
        pq.push({0,0});

        while(!pq.empty())
        {
            int nod = pq.top().second;
            pq.pop();
            if(vizitat[nod]) 
                continue;
            vizitat[nod] = 1;
            if(tati[nod] != -1)
                arborePartialCostMinim.push_back(muchieCost(tati[nod], nod, distanta[nod]));

            for(int j=0; j<n; j++)
            {
                // if there's a cost edge and not visited
                if(!vizitat[j] && matriceCost[nod][j] > 0 && matriceCost[nod][j] < distanta[j])
                {
                    distanta[j] = matriceCost[nod][j];
                    tati[j] = nod;
                    pq.push({distanta[j], j});
                }
            }
        }
    }

    //--------------------------------------------------------------------------------
    // Dijkstra for cost >= 0, using adjacency list of (cost, node)
    vector<int> solutieDijkstra;

    void Dijkstra(int start)
    {
        solutieDijkstra.assign(n, 0);
        distanta.assign(n, INT_MAX);
        tati.assign(n, 0);
        set<pair<int,int>> Q;
        distanta[start] = 0;
        Q.insert({0,start});

        while(!Q.empty())
        {
            auto topVal = *Q.begin();
            Q.erase(Q.begin());
            int nod=topVal.second;
            for(auto & p : listaAdiacentaCost[nod])
            {
                int cost = p.first;
                int x = p.second;
                if(distanta[x] > distanta[nod] + cost)
                {
                    if(distanta[x] != INT_MAX)
                        Q.erase({ distanta[x], x });
                    distanta[x] = distanta[nod] + cost;
                    tati[x] = nod;
                    Q.insert({ distanta[x], x });
                }
            }
        }

        for(int i=0; i<n; i++)
        {
            if(distanta[i] < INT_MAX)
                solutieDijkstra[i] = distanta[i];
            else
                solutieDijkstra[i] = 0;
        }
    }

    //--------------------------------------------------------------------------------
    // Bellman-Ford for edges with possible negative costs, but no negative cycles
    // adjacency matrix with costs used
    vector<int> solutieBellmanFord;

    bool BellmanFord(int start)
    {
        solutieBellmanFord.assign(n, INT_MAX);
        solutieBellmanFord[start] = 0;
        tati.assign(n, -1);
        vizitat.assign(n, false);

        vector<bool> inQueue(n,false);
        vector<int> proceseaza(n,0);
        queue<int> Q;
        Q.push(start);
        inQueue[start] = true;

        while(!Q.empty())
        {
            int u=Q.front(); 
            Q.pop();
            inQueue[u]=false;
            proceseaza[u]++;
            if(proceseaza[u]>n-1)
                return true; // negative cycle

            for(int v=0; v<n; v++)
            {
                if(matriceCost[u][v] != 0 && matriceCost[u][v] != INT_MAX)
                {
                    long long attempt = (long long)solutieBellmanFord[u] + matriceCost[u][v];
                    if(attempt < solutieBellmanFord[v])
                    {
                        solutieBellmanFord[v]= (int)attempt;
                        tati[v]=u;
                        if(!inQueue[v])
                        {
                            inQueue[v]=true;
                            Q.push(v);
                        }
                    }
                }
            }
        }

        return false; // no negative cycle
    }

    //--------------------------------------------------------------------------------
    // Floyd-Warshall (matrixCost). for negative or positive costs, no negative cycles
    vector<vector<int>> matriceCostMinim; 
    vector<vector<int>> parinteFloydWarshall;

    bool FloydWarshall()
    {
        matriceCostMinim = matriceCost;
        // init
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
            {
                if(i==j) matriceCostMinim[i][j] = 0;
                else if(matriceCostMinim[i][j]==0) matriceCostMinim[i][j] = INT_MAX;
            }
        }

        parinteFloydWarshall = vector<vector<int>>(n, vector<int>(n,-1));
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(matriceCostMinim[i][j]!=INT_MAX && i!=j)
                    parinteFloydWarshall[i][j]= i;

        // run FW
        for(int k=0; k<n; k++)
        {
            for(int i=0; i<n; i++)
            {
                if(matriceCostMinim[i][k]==INT_MAX) continue;
                for(int j=0; j<n; j++)
                {
                    if(matriceCostMinim[k][j]==INT_MAX) continue;
                    long long potential = (long long)matriceCostMinim[i][k]+matriceCostMinim[k][j];
                    if(potential < matriceCostMinim[i][j])
                    {
                        matriceCostMinim[i][j] = (int)potential;
                        parinteFloydWarshall[i][j]= parinteFloydWarshall[k][j];
                    }
                }
            }
        }

        // check negative cycles
        for(int i=0; i<n; i++)
            if(matriceCostMinim[i][i] < 0)
                return true; 
        return false;
    }

    void drumFloydWarshall(int x, int y)
    {
        if(x!=y)
            drumFloydWarshall(x, parinteFloydWarshall[x][y]);
        cout<< y <<" ";
    }

    //--------------------------------------------------------------------------------
    // example usage of edmond-karp is omitted, but you can add if needed...
    // ...
    // all done
    //--------------------------------------------------------------------------------

    // for demonstration, some placeholders:
    void apelareDFS()
    {
        orientat = false;
        citireMatriceAdiacenta();  // read from "cin"
        vizitat.resize(n,0);
        tati.resize(n,-1);
        timpDfs=0;
        matriceDFS(0);  // start from node 0
        // show dfs order
        cout<<"dfs order: ";
        for(int v: solutieDFS) cout<<v+1<<" ";
        cout<<"\nparents: ";
        for(int p: tati) cout<<p+1<<" "; // +1 if p!=-1
        cout<<"\n";
    }
};

int main()
{
    // example: we call the DFS usage
    Graf g;
    g.apelareDFS();
    return 0;
}
Leave a Comment