Cod sursa(job #2822285)

Utilizator Matei1905Matei Neagu Matei1905 Data 23 decembrie 2021 19:41:01
Problema Algoritmul Bellman-Ford Scor 15
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 21.52 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>

#define MAX 1000000000
#define MAXCAPACITY 200000
using namespace std;

ifstream f("bellmanford.in");
ofstream g("bellmanford.out");


void print_stack(stack<int>& nodes)
{
    while(!nodes.empty())
    {
        g << nodes.top() << ' ';
        nodes.pop();
    }
}


class Disjoint_Set_Forest{
    int N;
    vector<int> father;
    vector<int> height;
    public:

        Disjoint_Set_Forest(int = 0);
        int represents(int);
        void unite(int, int);
};


Disjoint_Set_Forest :: Disjoint_Set_Forest(int x): N(x) {
    father = vector<int> (N + 1);
    height = vector<int> (N + 1);
}


int Disjoint_Set_Forest :: represents(int curr)
{
    if(father[curr] == 0)
        return curr;
    
    int f = represents(father[curr]);
    father[curr] = f;
    return f;
}


void Disjoint_Set_Forest :: unite(int x, int y)
{
    if(height[x] < height[y])
        father[x] = y;
    else
        father[y] = x;
 
    if(height[x] == height[y])
        height[x] ++;
}


class Graph
{
    int N, M;

    vector<int> nodesInfo;
    queue<int> Q;
    vector<pair<int, pair<int, int>>> weightedEdges;            //first -> edge cost, second -> nodes in edge
    vector<vector<pair<int, int>>> weightedNeighbours;          // first -> edge weight ; second -> 2nd node in edge
    vector<vector<int>> edges;

    public:
        Graph() = default;

        void set_unoriented_edge(int, int);
        void set_oriented_edge(int, int);

        void init_edges();

        void set_nodesInfo(int);
        void set_fathers(vector<int>&);

        void read_N();
        void read_M();

        int get_N();
        int get_node_info(int);
        void set_node_info(int, int);

        void read_edges();      // use when edges are given in the form of adjacency list
        void read_edges_oriented();
        void read_edges_oriented_with_reversed(vector<vector<int>>&);
        
        void read_edges_matrix();       // edges are given in the form of adjacency matrix
        void read_weightedEdges();
        void read_weightedNeighbours();
        void read_edges_flow(vector<vector<int>>&);

        void print_message(string);
        void print_array(vector<int>, int);
        void print_nodesInfo(int, int, int);

        void BFS(int);
        void DFS(int);
        void DFS_kosaraju(int, vector<vector<int>>&, vector<int>&);
        
        void biconnected_utility(int, stack<int>&, vector<int>&, vector<vector<int>>&, int&);
        void biconnected();
        void strongly_connected();
        void top_sort_utility(int, stack<int>&);
        void topological_sort();
        void havel_hakimi();
        void critical(int, int, vector<vector<int>>&, vector<int>&);
        void bridges();
        void kruskal();
        void dijkstra(int);
        void bellman_ford();
        void edmonds_karp();
        void graph_diameter();
        void roy_floyd();
        void euler_cycle();
};


void Graph :: init_edges() { edges = vector<vector<int>> (N + 1);}
void Graph :: set_nodesInfo(int value) { nodesInfo = vector<int> (N + 1, value); }
void Graph :: set_fathers(vector<int>& fathers) { fathers = vector<int> (N + 1);}


void Graph :: set_unoriented_edge(int x, int y) { edges[x].push_back(y); edges[y].push_back(x); }
void Graph :: set_oriented_edge(int x, int y) { edges[x].push_back(y); }


void Graph :: read_N() { f >> N; }
void Graph :: read_M() { f >> M; }


int Graph :: get_N() { return N; }
int Graph :: get_node_info(int x) { return nodesInfo[x]; }
void Graph :: set_node_info(int x, int val) { nodesInfo[x] = val; }


void Graph :: read_edges_matrix()
{
    int i, j;
    for(i = 1; i <= N; i++)
        edges[i] = vector<int> (N + 1);
    
    for(i = 1; i <= N; i++)
        for(j = 1; j <= N; j++)
        {
            f >> edges[i][j];
            if(edges[i][j] == 0 && i != j)
                edges[i][j] = MAX;
        }
}


void Graph :: read_edges()
{
    int i, x, y;
    for(i = 1; i <= M; i++)
    {
        f >> x >> y;
        set_unoriented_edge(x, y);
    }
}


void Graph :: read_edges_oriented()
{
    int i, x, y;
    for(i = 1; i <= M; i++)
    {
        f >> x >> y;
        set_oriented_edge(x, y);
    }
}


void Graph :: read_edges_oriented_with_reversed(vector<vector<int>>& reversed)
{
    int i, x, y;
    for(i = 1; i <= M; i++)
    {
        f >> x >> y;
        set_oriented_edge(x, y);
        reversed[y].push_back(x);
    }
}


void Graph :: read_weightedEdges()
{
    read_N();
    read_M();

    int i, x, y, c;
    for(i = 1; i <= M; i++)
    {
        f >> x >> y >> c;
        weightedEdges.push_back(make_pair(c, make_pair(x, y)));
    }
}


void Graph :: read_weightedNeighbours()
{
    read_N();
    read_M();

    weightedNeighbours = vector<vector<pair<int, int>>> (N + 1);    // first -> edge weight ; second -> 2nd node in edge

    int i, x, y, c;
    for(i = 1; i <= M; i++)
    {
        f >> x >> y >> c;
        weightedNeighbours[x].push_back(make_pair(c, y));
    }
}


void Graph :: read_edges_flow(vector<vector<int>>& flow)
{
    f >> N >> M;
    edges = vector<vector<int>> (N + 1);
    flow = vector<vector<int>> (N + 1);

    int i, x, y, c;
    
    for(i = 1; i <= N; i++)
        flow[i] = vector<int> (N + 1);

    for(i = 1; i <= M; i++)
    {
        f >> x >> y >> c;
        edges[x].push_back(y);
        edges[y].push_back(x);

        flow[x][y] = c;
    }
}


void Graph :: print_message(string m) { g << m; }


void Graph :: print_array(vector<int> solution, int start)
{
    for(int i = start; i < solution.size(); i ++)
    {
        g << solution[i] << ' ';
    }
}


void Graph :: print_nodesInfo(int start, int replaced, int replaceWith)
{
    for(int i = start; i <= N; i++)
        if(nodesInfo[i] == replaced)
            g << replaceWith << " ";
        else
            g << nodesInfo[i] << " ";
}


void Graph :: BFS(int start)
{
    nodesInfo[start] = 0;
    Q.push(start);
    int curr, i, following;
    while(!Q.empty())
    {
        curr = Q.front();
        Q.pop();
        for(i = 0; i < edges[curr].size(); i++)
        {
            following = edges[curr][i];
            if(nodesInfo[following] == MAX)
            {
                Q.push(following);
                nodesInfo[following] = nodesInfo[curr] + 1;
            }
            else if(nodesInfo[curr] + 1 < nodesInfo[following])
                nodesInfo[following] = nodesInfo[curr] + 1;
        }
    }
}


void Graph :: DFS(int curr)
{
    for(int i = 0; i < edges[curr].size(); i++)
        if(nodesInfo[edges[curr][i]] == 0)
        {
            nodesInfo[edges[curr][i]] = 1;
            DFS(edges[curr][i]);
        }
}


void Graph :: biconnected_utility(int curr, stack<int>& nodes, vector<int>& earliest, vector<vector<int>>& solution, int& K)
{
    int subComponents = 0, following;
 
    for(int i = 0; i < edges[curr].size(); i++)
    {
        following = edges[curr][i];
        if(nodesInfo[following] == 0)
        {
            subComponents += 1;
 
            nodes.push(following);
            nodesInfo[following] = nodesInfo[curr] + 1;
            earliest[following] = nodesInfo[curr];
 
            biconnected_utility(following, nodes, earliest, solution, K);
 
            if(subComponents > 1 && nodesInfo[curr] == 1)       // the only link between {{v[curr][i] and the nodes that follow it}} and {{the nodes already visited}}
                                    // is through curr => curr is a critical point => from v[curr][i] onwards we have a new biconnected component
            {
                solution.push_back(vector<int>());
                while(!(nodes.top() == following))
                {
                    solution[K].push_back(nodes.top());
                    nodes.pop();
                }
                solution[K].push_back(nodes.top());
                nodes.pop();
                solution[K].push_back(curr);        // curr (the top level node) was part of the biconnected component which was just visited in the recursion, but it will
                                                // also be in the biconnected component with the nodes previous to that, so we keep curr in the stack, adding it sepparately
                K++;
            }
 
            if(nodesInfo[curr] <= earliest[following] && nodesInfo[curr] > 1)
            {
                solution.push_back(vector<int>());
                while(!(nodes.top() == following))
                {
                    solution[K].push_back(nodes.top());
                    nodes.pop();
                }
                solution[K].push_back(nodes.top());
                nodes.pop();
                solution[K].push_back(curr);
                K++;
            }
            else
                earliest[curr] = min(earliest[following], earliest[curr]);
            // if curr is the first node, the last biconnected component will remain in the stack bc the program won't go to line 30 again, and we'll empty it in main()
        }
        else
        {
            earliest[curr] = min(earliest[curr], nodesInfo[following]);
        }
    }
}

void Graph :: biconnected()
{
    read_N();
    read_M();

    init_edges();
    read_edges();
    set_nodesInfo(0);       // nodesInfo will represent the time when nodes were discovered

    vector<int> earliest = vector<int> (N + 1);        // the earliest time of a node to which a node can go back to
    stack<int> nodes;
    vector<vector<int>> solution;
    int i, K = 0;

    for(i = 1; i <= N; i++)
    {
        if (nodesInfo[i] == 0)
        {
            nodesInfo[i] = earliest[i] = 1;
            nodes.push(i);
            biconnected_utility(i, nodes, earliest, solution, K);
        }
        if(!nodes.empty())
        {
            solution.push_back(vector<int>());
            while(!nodes.empty())
            {
                solution[K].push_back(nodes.top());
                nodes.pop();
            }
            K++;
        }
    }
 
    g << K << '\n';
    for(i = 0; i < K; i++)
    {
        for (int j = 0; j < solution[i].size(); j++)
        {
            g << solution[i][j] << ' ';
        }
        g << '\n';
    }
}


void Graph :: DFS_kosaraju(int curr, vector<vector<int>>& reversed, vector<int>& aux)
{
    nodesInfo[curr] = 2;
    int x;
    for(int j = 0; j < reversed[curr].size(); j++)
    {
        x = reversed[curr][j];
        if(nodesInfo[x] == 1)
        {
            DFS_kosaraju(x, reversed, aux);
        }
    }
    aux.push_back(curr);
}


void Graph :: strongly_connected()
{
    read_N();
    read_M();

    init_edges();
    vector<vector<int>> reversed = vector<vector<int>>(N + 1);
    read_edges_oriented_with_reversed(reversed);

    int i;
    set_nodesInfo(0);      //nodesInfo is used as the vector for "visited"

    // kosaraju

    stack<int> nodes;
    for(i = 1 ; i <= N; i++)
    {
        if(nodesInfo[i] == 0)
            top_sort_utility(i, nodes);
    }
 
    int scc = 0;
    vector<int> aux;
    vector<vector<int>> solution;

    while(!nodes.empty())
    {
        if(nodesInfo[nodes.top()] == 1)
        {
            aux = vector<int>();
            DFS_kosaraju(nodes.top(), reversed, aux);
            solution.push_back(aux);
            scc ++;
        }
        nodes.pop();
    }
    g << scc << '\n';
 
    for(i = 0; i < solution.size(); i++)
    {
        for(int j = 0; j < solution[i].size(); j++)
            g << solution[i][j] << ' ';
        g << '\n';
    }
}


void Graph :: top_sort_utility(int curr, stack<int>& nodes)
{
    nodesInfo[curr] = 1;
    int x;
    for(int i = 0; i < edges[curr].size(); i++)
    {
        x = edges[curr][i];
        if(nodesInfo[x] == 0)
            top_sort_utility(x, nodes);
    }

    nodes.push(curr);
}

void Graph :: topological_sort()
{
    read_N();
    read_M();
    init_edges();
    read_edges_oriented();
    set_nodesInfo(0);           // nodesInfo is used as "visited"

    stack<int> nodes;

    for(int i = 1; i <= N; i++)
    {
        if(nodesInfo[i] == 0)
            top_sort_utility(i, nodes);
    }

    print_stack(nodes);
}


void Graph :: havel_hakimi()
{
    read_N();
    int i, x, j;
    for(i = 1; i <= N; i++)
    {
        f >> x;
        nodesInfo.push_back(x);
    }

    while(true)
    {
        sort(nodesInfo.begin(), nodesInfo.end());
        i = nodesInfo.size() - 1;
        if(nodesInfo[i] == 0)     // every node has degree 0 so the graph can be made
        {
            print_message("Yes.");
            break;
        }
        j = i - 1;
        while(j >= 0 && nodesInfo[i] > 0)
        {
            nodesInfo[j]--;
            nodesInfo[i]--;
            if(nodesInfo[j] < 0)
            {
                print_message("No!");
                return;
            }
            j--;
        }
        if(j == -1 && nodesInfo[i] > 0)
        {
            print_message("No!");
            break;
        }
        nodesInfo.pop_back();
    }
}


void Graph :: critical(int curr, int father, vector<vector<int>>& sol, vector<int>& upwards)
{
    int i, x;
    for(i = 0; i < edges[curr].size(); i++)
    {
        x = edges[curr][i];
        if (nodesInfo[x] == 0)
        {
            nodesInfo[x] = upwards[x] = nodesInfo[curr] + 1;
            critical(x, curr, sol, upwards);
            if(upwards[curr] > upwards[x])
                upwards[curr] = upwards[x];
        }
        else
            if(x != father && father != -1)
                if(upwards[curr] > nodesInfo[x])
                    upwards[curr] = nodesInfo[x];
    }
    if(nodesInfo[curr] == upwards[curr] && father != -1)
        sol.push_back(vector<int> {father, curr});
            
}


void Graph :: bridges()
{
    read_N();
    read_M();
    init_edges();
    read_edges();
    set_nodesInfo(0);       // nodesInfo[x] -> the level of node x in DFS tree

    vector<int> upwards = vector<int> (N);
    vector<vector<int>> sol;
    nodesInfo[0] = upwards[0] = 1;
    critical(0, -1, sol, upwards);
    
    for(int i = 0; i < sol.size(); i++)
        g << sol[i][0] << ' ' << sol[i][1] << '\n';
}


void Graph :: kruskal()
{
    read_weightedEdges();
    Disjoint_Set_Forest d(N);
    vector<pair<int, int>> solution;

    int totalCost = 0, j = 0;
    sort(weightedEdges.begin(), weightedEdges.end());
    int i;

    for(i = 1; i <= N - 1; i++)
    {
        while(!(d.represents(weightedEdges[j].second.first) != d.represents(weightedEdges[j].second.second)))
            j++;
        totalCost += weightedEdges[j].first;
        solution.push_back(weightedEdges[j].second);
 
 
        d.unite(d.represents(weightedEdges[j].second.first), d.represents(weightedEdges[j].second.second));
    }
 
    g << totalCost << '\n' << N - 1 << '\n';
    for(i = 0; i < solution.size(); i++)
        g << solution[i].first << ' ' << solution[i].second << '\n';
}


void Graph :: dijkstra(int start)
{
    read_weightedNeighbours();
    set_nodesInfo(MAX);       // nodesInfo[x] == distance to node x

    vector<int> selected = vector<int>(N + 1);
    pair<int, int> edg;
    priority_queue<pair<int,int>> pq;

    nodesInfo[start] = 0;
    pq.push(make_pair(0, start));
 
    int x, c, i;
    while(!pq.empty())
    {
        x = pq.top().second;
        c = -pq.top().first;
        pq.pop();
 
        if(selected[x] == 0)
        {
            selected[x] = 1;
 
            for(i = 0; i < weightedNeighbours[x].size(); i++)
            {
                edg = weightedNeighbours[x][i];
                if(selected[edg.second] == 0)
                {
                    if(c + edg.first < nodesInfo[edg.second])
                    {
                        nodesInfo[edg.second] = c + edg.first;
                        pq.push(make_pair(-nodesInfo[edg.second], edg.second));
                    }
                }
            }
        }
    }
 
    print_nodesInfo(2, MAX, 0);
}


void Graph :: bellman_ford()
{
    read_weightedNeighbours();
    set_nodesInfo(0);

    vector<int> distances = vector<int> (N + 1, MAX);
    distances[1] = 0;
    nodesInfo[1] = 1;       // if nodesInfo[x] is > 0, then x is currently in the Q. otherwise, it's not
    Q.push(1);              //Q contains the nodes that were recently updated and whose neighbours need updates accordingly

    int j, c, u, v;
    while(!Q.empty())
    {
        u = Q.front();
        nodesInfo[u] = -nodesInfo[u];
        Q.pop();

        for(j = 0; j < weightedNeighbours[u].size(); j++)
        {
            c = weightedNeighbours[u][j].first;
            v = weightedNeighbours[u][j].second;
            if(distances[u] + c < distances[v])
            {
                distances[v] = distances[u] + c;
                if(nodesInfo[v] <= 0)       //v is not currently in Q
                {
                    Q.push(v);
                    nodesInfo[v] = -nodesInfo[v] + 1;
                    if(nodesInfo[v] == N)           //nodesInfo[x] = how many times x was added to Q. the maximum length of a chain of vortexes is N - 1. if we have N vortexes
                                                //then we no longer have a chain (we have a cycle somewhere in it). so if we add x N times to Q, something's wrong
                    {
                        print_message("Ciclu negativ!");
                        return;
                    }
                }
            }
        }
    }

    print_array(distances, 2);
}


void Graph :: edmonds_karp()
{
    vector<vector<int>> flow;
    read_edges_flow(flow);
    set_nodesInfo(0);
    vector<int> fathers;
    set_fathers(fathers);

    int maxFlow = 0, iteration = 1, curr, i, mini = MAXCAPACITY, following;    
    while(true)
    {
        Q.push(1);
        nodesInfo[1] = iteration;
        mini = MAXCAPACITY;

        while(!Q.empty())
        {
            curr = Q.front();
            Q.pop();
            for(i = 0; i < edges[curr].size(); i++)
            {
                following = edges[curr][i];
                if(nodesInfo[following] != iteration && flow[curr][following] > 0)
                {
                    Q.push(following);
                    fathers[following] = curr;
                    nodesInfo[following] = iteration;
                    if(following == N)
                    {
                        Q = queue<int>();
                        break;
                    }
                }
            }
        }

        if(nodesInfo[N] != iteration)
            { g << maxFlow; return; }

        curr = N;
        while(curr != 1) 
        {       
            mini = min(mini, flow[fathers[curr]][curr]);
            curr = fathers[curr];
        }
        maxFlow += mini;
        curr = N;
        while(curr != 1)
        {
            flow[fathers[curr]][curr] -= mini;
            flow[curr][fathers[curr]] += mini;
            curr = fathers[curr];
        }
        
        iteration++;     
    }

}


void Graph :: graph_diameter()
{
    read_N();
    M = N - 1;
    init_edges();
    read_edges();
    set_nodesInfo(MAX);

    BFS(1);
    int maxi = 0, nod1 = 1;
    for(int i = 1; i <= N; i++)
        if(nodesInfo[i] > maxi)
        {
            maxi = nodesInfo[i];
            nod1 = i;
        }
    
    set_nodesInfo(MAX);
    BFS(nod1);

    maxi = 0;
    for(int i = 1; i <= N; i++)
        if(nodesInfo[i] > maxi)
        {
            maxi = nodesInfo[i];
            nod1 = i;
        }

    g << maxi + 1;
}


void Graph :: roy_floyd()
{
    read_N();
    init_edges();
    read_edges_matrix();

    int i, j, k;
    for(k = 1; k <= N; k++)
        for(i = 1; i <= N; i++)
        {
            if(i == k) continue;
            for(j = 1; j <= N; j++)
                edges[i][j] = min(edges[i][j], edges[i][k] + edges[k][j]);
        }

    for(i = 1; i <= N; i++)
    {
        for(j = 1; j <= N; j++)
            if(edges[i][j] == MAX)
                g << "0 ";
            else
                g << edges[i][j] << ' ';
        g << '\n';
    }
}


void BFS_infoarena(Graph gr)
{
    gr.read_N();
    gr.read_M();

    int start;
    f >> start;

    gr.set_nodesInfo(MAX);
    gr.init_edges();
    gr.read_edges_oriented();


    gr.BFS(start);
    
    gr.print_nodesInfo(1, MAX, -1);

}


void DFS_infoarena(Graph gr)
{
    gr.read_N();
    gr.read_M();

    gr.set_nodesInfo(0);
    gr.init_edges();
    gr.read_edges();

    int conexElements = 0;
    for(int i = 1; i <= gr.get_N(); i++)
    {
        if (gr.get_node_info(i) == 0)
        {
            gr.set_node_info(i, 1);
            conexElements ++;
            gr.DFS(i);
        }
    }
    g << conexElements;
}


void disjoint_infoarena()
{
    int N, M;
    f >> N >> M;
    Disjoint_Set_Forest d(N);

    int i, op, x, y;
    for(i = 1; i <= M; i++)
    {
        f >> op >> x >> y;
        if(op == 1)
        {
            d.unite(d.represents(x), d.represents(y));
        }
        else
            if(d.represents(x) == d.represents(y))
                g << "DA\n";
            else
                g << "NU\n";
    }
}


int main()
{
    Graph gr;
    gr.dijkstra(1);
    return 0;
}