Cod sursa(job #2796355)

Utilizator Dantelogus99Gruia Gabriel Dantelogus99 Data 7 noiembrie 2021 22:32:30
Problema Algoritmul Bellman-Ford Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 17.75 kb
#include <fstream>
#include <iostream>
#include <vector>
#include <list>
#include <stack>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;

#define INF 2147483647

//enum properties { Directed = true, unDirected = false, Weighted = true, unWeighted = false };


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

//ifstream fin("input");
//ofstream fout("output");



class Graph
{
// Implementation of  << UTILITARY Functions >>  for (UN)Directed & (UN)Weighted  << Graphs >>;

#pragma region Data

    int nrNodes;
    int nrEdges;
    bool isDirected;
    bool isWeighted;

    vector<list<pair<int, int>>> adjacencyList;

#pragma endregion


public:

#pragma region IO_Methods

    Graph(int n = 0, int m = 0, bool d = false, bool w = false) : nrNodes(n), nrEdges(m), isDirected(d), isWeighted(w) {}

    void readAdjacencyList()
    {
        adjacencyList.resize(nrNodes + 1);

        if (!isWeighted)
        {
            int x, y;

            if (!isDirected)
            {
                for (int i = 0; i < nrEdges; i++)
                {
                    fin >> x >> y;
                    adjacencyList[x].push_back(make_pair(y, 0));
                    adjacencyList[y].push_back(make_pair(x, 0));
                }
            }
            else
            {
                for (int i = 0; i < nrEdges; i++)
                {
                    fin >> x >> y;
                    adjacencyList[x].push_back(make_pair(y, 0));
                }
            }
        }
        else
        {
            int x, y, c;

            if (!isDirected)
            {
                for (int i = 0; i < nrEdges; i++)
                {
                    fin >> x >> y >> c;
                    adjacencyList[x].push_back(make_pair(y, c));
                    adjacencyList[y].push_back(make_pair(x, c));
                }
            }
            else
            {
                for (int i = 0; i < nrEdges; i++)
                {
                    fin >> x >> y >> c;
                    adjacencyList[x].push_back(make_pair(y, c));
                }
            }
        }
    }

    void printAdjacencyList()
    {
        fout << "\n>   nrNodes = " << nrNodes;
        fout << "\n>   nrEdges = " << nrEdges;

        fout << "\n\n\n>   The ADJACENCY LIST associated to the";
        isDirected ? fout << "DIRECTED" : fout << "UNDIRECTED";
        isWeighted ? fout << ", WEIGHTED" : fout << ", UNWEIGHTED";
        fout << " graph <G>:";

        for (int i = 1; i <= nrNodes; i++)
        {
            if (adjacencyList[i].size())
            {
                if (!isWeighted)
                {
                    fout << "\n\nNode " << i << ":    ";
                    for (auto x : adjacencyList[i])
                        fout << x.first << " ";
                }
                else
                {
                    fout << "\n\nNode " << i << ":\n";
                    for (auto x : adjacencyList[i])
                        fout << "     " << i << " --> (" << x.second << ") --> " << x.first << "\n";
                }
            }
        }
    }

#pragma endregion

#pragma region Unweighted_Graph_Methods

    vector<int> getUnweightedDistances(int startingNode)
    {
        vector<bool> isVisited(nrNodes + 1, false);
        vector<int> distances(nrNodes + 1, -1);

        BFS(startingNode, isVisited, distances);

        return distances;
    }

    list<set<int>> getConnectedComponents()
    {
        list<set<int>> CClist;
        vector<bool> isVisited(nrNodes + 1, false);

        for (int i = 1; i <= nrNodes; i++) // parcurgem nodurile pana gasim unul nevizitat, indicand o noua componenta conexa, si pornim DFS din acel nod
            if (!isVisited[i])
            {
                set<int> connectedComponent;
                DFS(i, isVisited, connectedComponent);

                CClist.push_back(connectedComponent);
            }

        return CClist;
    }

    list<set<int>> getStronglyConnectedComponents()
    {
        list<set<int>> SCClist;

        vector<int> discoveryOrder(nrNodes + 1, 0);
        vector<int> lowestLink(nrNodes + 1, 0);
        vector<bool> onStack(nrNodes + 1, false);
        stack<int> path;

        for (int i = 1; i <= nrNodes; i++)
            if (!discoveryOrder[i])
                TarjanDFS(i, discoveryOrder, lowestLink, path, onStack, SCClist);

        return SCClist;
    }

    list<set<int>> getBiconnectedComponents()
    {
        list<set<int>> BCClist;

        vector<int> levels(nrNodes + 1, 0);
        vector<int> lowestLink(nrNodes + 1, 0);
        stack<int> path;

        BiconnectedDFS(1, 1, levels, lowestLink, path, BCClist);

        return BCClist;
    }

    list<pair<int, int>> getCriticalEdges()
    {
        list<pair<int, int>> CElist;

        vector<int> discoveryOrder(nrNodes + 1, 0);
        vector<int> lowestLink(nrNodes + 1, 0);

        CriticalEdgesDFS(1, 0, discoveryOrder, lowestLink, CElist);

        return CElist;
    }

    list<int> getTopologicalOrder()
    {
        list<int> TOlist;
        vector<bool> isVisited(nrNodes + 1, false);

        for (int i = 1; i <= nrNodes; i++)
            if (!isVisited[i])
                TopologicalOrderDFS(i, isVisited, TOlist);

        return TOlist;
    }

    bool getValidGraph()
    {
        vector<int> degrees;

        int deg;
        while (fin >> deg)
        {
            degrees.push_back(deg);
        }

        while (!degrees.empty())
        {
            sort(degrees.begin(), degrees.end(), greater<>());

            if (degrees[0] == 0)
                return true;

            if (degrees[0] > degrees.size() - 1)
                return false;

            for (int i = 1; i <= degrees[0]; i++)
            {
                degrees[i]--;

                if (degrees[i] < 0)
                    return false;
            }

            degrees.erase(degrees.begin() + 0);
        }
    }

#pragma endregion

#pragma region Weighted_Graph_Methods

    vector<int> getWeightedDistances(int startingNode)
    {
        vector<int> distance(nrNodes + 1, INF);
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> inProcessing;

        Dijkstra(startingNode, inProcessing, distance);

        return distance;
    }

    vector<int> getBellmanFordDistances(int startingNode)
    {
        vector<int> distance(nrNodes + 1, INF);

        BellmanFord(startingNode, distance);

        return distance;
    }

#pragma endregion


private:

#pragma region Private_Methods

    void BFS(int startingNode, vector<bool>& isVisited, vector<int>& dist)
    {
        queue<int> inProcessing;

        inProcessing.push(startingNode);
        isVisited[startingNode] = true; // adaugam nodul de plecare in coada; pornim BFS
        dist[startingNode] = 0;

        while (!inProcessing.empty())
        {
            int currentNode = inProcessing.front(); // extragem primul nod din coada si ii parcurgem/adaugam vecinii in coada

            inProcessing.pop();

            for (auto adjNode : adjacencyList[currentNode]) // vecin.first = nodul din lista de adiacenta a nodului curent
                if (!isVisited[adjNode.first])               // adauga toti vecinii nevizitati ai nodului curent in coada
                {
                    inProcessing.push(adjNode.first);
                    isVisited[adjNode.first] = true;
                    dist[adjNode.first] = dist[currentNode] + 1;
                } 
        }

        dist.erase(dist.begin());
    }

    void DFS(int startingNode, vector<bool>& isVisited, set<int>& connectedComponent)
    {
        isVisited[startingNode] = true;
        connectedComponent.insert(startingNode);

        for (auto adjNode : adjacencyList[startingNode]) // vecin.first = nodul din lista de adiacenta a nodului curent
            if (!isVisited[adjNode.first])          // parcurgem componenta conexa de care apartine nodul de pornire
                DFS(adjNode.first, isVisited, connectedComponent);
    }

    void TarjanDFS(int currentNode, vector<int>& discOrder, vector<int>& lowLink, stack<int>& path, vector<bool>& onStack, list<set<int>>& SCClist)
    {
        static int currentID = 1;
        path.push(currentNode);
        onStack[currentNode] = true;
        discOrder[currentNode] = lowLink[currentNode] = currentID++;

        for (auto adjNode : adjacencyList[currentNode]) // vecin.first = nodul din lista de adiacenta a nodului curent
        {
            if (discOrder[adjNode.first]) // daca nodul vecin a fost explorat si se afla pe stiva de ordine, il incadram intr-o componenta conexa;
            {
                if (onStack[adjNode.first])
                    lowLink[currentNode] = min(lowLink[currentNode], discOrder[adjNode.first]);
            }
            else  // daca nodul vecin nu a fost explorat, pornim DFS din el, iar la revenirea din recursie, il incadram intr-o componenta conexa;
            {
                TarjanDFS(adjNode.first, discOrder, lowLink, path, onStack, SCClist);
                lowLink[currentNode] = min(lowLink[currentNode], lowLink[adjNode.first]);
            }
        }

                                                             // daca ID - ul nodului corespunde cu lowLink - value - ul sau, inseamna ca nodul este radacina componentei sale conexe,
        if (lowLink[currentNode] == discOrder[currentNode])  // si putem scoate de pe stiva toate nodurile pana la startingNode, deoarece am terminat de explorat componenta respectiva;
        {
            set<int> connectedComp;
            int last;

            do
            {
                last = path.top();
                path.pop();
                onStack[last] = false;

                connectedComp.insert(last);
            } while (currentNode != last);

            SCClist.push_back(connectedComp);
        }
    }

    void BiconnectedDFS(int currentNode, int currentLevel, vector<int>& level, vector<int>& lowLink, stack<int>& path, list<set<int>>& BCClist)
    {
        path.push(currentNode); // stiva retine parcurgerea DFS a subarborilor grafului
        level[currentNode] = lowLink[currentNode] = currentLevel; // adancimi[x] = nivelul de adancime al nodului X din arborele DFS;     lowLink[x] = adancimea minima la care se poate intoarce nodul X;

        for (auto adjNode : adjacencyList[currentNode])
        {
            if (level[adjNode.first]) // daca nodul vecin a fost explorat
            {
                lowLink[currentNode] = min(lowLink[currentNode], level[adjNode.first]); // adancimea minima a nodului curent S = min (adancimea sa minima curenta; adancimea vecinilor sai)
            }
            else
            {
                BiconnectedDFS(adjNode.first, currentLevel + 1, level, lowLink, path, BCClist);
                lowLink[currentNode] = min(lowLink[currentNode], lowLink[adjNode.first]); // la intoarcerea din recursie, nodurile cu adancimea < adancimea nodului pe care s-a facut recursia
                                                                         // isi minimizeaza adancimea minima lowLink cu a succesorilor;
                if (lowLink[adjNode.first] == level[currentNode])
                {                                          // cand ajungem la succesorul radacinii componentei, eliminam nodurile pana la radacina din stiva, formand o componenta biconexa;
                    set<int> biconnectedCopm;
                    int last;

                    do
                    {
                        last = path.top();
                        path.pop();

                        biconnectedCopm.insert(last);
                    } while (currentNode != last);

                    path.push(currentNode);

                    BCClist.push_back(biconnectedCopm);
                }
            }
        }
    }

    void CriticalEdgesDFS(int startingNode, int previous, vector<int>& discOrder, vector<int>& lowLink, list<pair<int, int>>& CElist)
    {
        static int currentID = 1;
        discOrder[startingNode] = lowLink[startingNode] = currentID++;

        for (auto adjNode : adjacencyList[startingNode])
        {
            if (discOrder[adjNode.first])
            {
                if (adjNode.first != previous)
                    lowLink[startingNode] = min(lowLink[startingNode], discOrder[adjNode.first]);
            }
            else
            {
                CriticalEdgesDFS(adjNode.first, startingNode, discOrder, lowLink, CElist);

                lowLink[startingNode] = min(lowLink[startingNode], lowLink[adjNode.first]);

                if (lowLink[adjNode.first] > discOrder[startingNode])
                    CElist.push_back(make_pair(startingNode, adjNode.first));
            }      
        }
    }

    void TopologicalOrderDFS(int startingNode, vector<bool>& isVisited, list<int>& TOlist)
    {
        isVisited[startingNode] = true;

        for (auto adjNode : adjacencyList[startingNode])
            if (!isVisited[adjNode.first])
                TopologicalOrderDFS(adjNode.first, isVisited, TOlist);

        TOlist.push_front(startingNode);
    }

    void Dijkstra(int startingNode, priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>>& inProcessing, vector<int>& dist)
    {
        dist[startingNode] = 0;
        inProcessing.push(make_pair(0, startingNode));

        while (!inProcessing.empty())
        {
            int nearestNode = inProcessing.top().second;
            int currentDistance = inProcessing.top().first;
            inProcessing.pop();

            if (currentDistance <= dist[nearestNode])
            {
                for (auto adjNode : adjacencyList[nearestNode])
                {
                    int node = adjNode.first;
                    int cost = adjNode.second;

                    if (dist[node] == INF && dist[nearestNode] + cost < dist[node])
                    {
                        dist[node] = dist[nearestNode] + cost;
                        inProcessing.push(make_pair(dist[node], node));
                    }
                }
            }
        }

        for (auto& d : dist)
            d == INF ? d : 0;

        dist.erase(dist.begin(), dist.begin() + 2);
    }

    void BellmanFord(int startingNode, vector<int>& dist)
    {
        queue<int> processingQueue;
        vector<bool> inQueue(nrNodes + 1, false);
        vector<int> countIterations(nrNodes + 1, 0);

        dist[startingNode] = 0;
        processingQueue.push(startingNode);
        inQueue[startingNode] = true;


        while (!processingQueue.empty())
        {
            int currentNode = processingQueue.front();
            processingQueue.pop();
            inQueue[currentNode] = false;

            countIterations[currentNode]++;
            if (countIterations[currentNode] >= nrNodes)
                break;

            for (auto adjNode : adjacencyList[currentNode])
            {
                int node = adjNode.first;
                int cost = adjNode.second;

                if (dist[node] > dist[currentNode] + cost)
                {
                    dist[node] = dist[currentNode] + cost;

                    if (!inQueue[node])
                    {
                        processingQueue.push(node);
                        inQueue[node] = true;
                    }
                }
            }
        }

        dist[0] = 0;
    }

#pragma endregion

};



int main()
{
    int nodes, edges, start;
    fin >> nodes >> edges;

    Graph G(nodes, edges, true, true); // G(nodes, edges, isDirected, isWeighted);

    G.readAdjacencyList();
    //G.printAdjacencyList();


#pragma region Public_Methods_Calls

/* ---> MINIMAL DISTANCES (UNWEIGHTED) <--- */

    /*vector<int> minDistances_UW = G.getUnweightedDistances(s);

    for (auto dist : minDistances_UW)
        fout << dist << " ";*/


/* ---> CONNECTED COMPONENTS <--- */

    /*list<set<int>> CClist = G.getConnectedComponents();

    fout << CClist.size();*/


/* ---> STRONGLY CONNECTED COMPONENTS <--- */

    /*list<set<int>> SCClist = G.getStronglyConnectedComponents();

    fout << SCClist.size() << "\n";

    for (auto SCC : SCClist)
    {
        for (auto node : SCC)
            fout << node << " ";
        fout << "\n";
    }*/


/* ---> BICONNECTED COMPONENTS <--- */

    /*list<set<int>> BCClist = G.getBiconnectedComponents();

    fout << BCClist.size() << "\n";

    for (auto BCC : BCClist)
    {
        for (auto node : BCC)
            fout << node << " ";
        fout << "\n";
    }*/


/* ---> CRITICAL EDGES <--- */

    /*list<pair<int, int>> CElist = G.getCriticalEdges();

    fout << CElist.size() << "\n";

    for (auto edge : CElist)
        fout << "(" << edge.first << " " << edge.second << ")" << "\n";*/


/* ---> TOPOLOGICAL ORDER <--- */

    /*list<int> TOlist = G.getTopologicalOrder();

    for (auto node : TOlist)
        fout << node << " ";*/


/* ---> GRAPHICAL SEQUENCE <-- - */

    /*bool HH = G.getValidGraph();

    HH ? fout << "Yes" : fout << "No";*/


/* ---> MINIMAL DISTANCES (WEIGHTED) <--- */

    /*vector<int> minDistances_W = G.getWeightedDistances(1);

    for (auto dist : minDistances_W)
        fout << dist << " ";*/


/* ---> MINMAL DISTANCES (W/ NEGATIVE COSTS) <--- */

    vector<int> minDistances_NegC = G.getBellmanFordDistances(1);

    if (!minDistances_NegC[0])
        fout << "Ciclu infinit!";
    else
        for (int i = 2; i < nodes; i++)
            fout << minDistances_NegC[i] << " ";

#pragma endregion
}