Cod sursa(job #2959448)

Utilizator VladWero08Olaeriu Vlad Mihai VladWero08 Data 31 decembrie 2022 10:52:58
Problema Cuplaj maxim in graf bipartit Scor 14
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.7 kb
#include <bits/stdc++.h>

using namespace std;

int Nodes, NodesL, NodesR, Edges;
vector<int> *AdjacencyList, *AdjacencyInnerList;
// Cost matrix, flux matrix
long **flux, **cost;

bool FindUnsaturatedPath(int Source, int Destination, int Nodess, vector<int> *AdList, vector <int> *AdInList, long **flux, long **cost, int *dad, int *visited){
    queue <int> Q;
    int Node;

    for(int i = 0; i <= Nodess; i++){
        visited[i] = dad[i] = 0;
    }

    // Add the source in the queue
    Q.push(Source);
    // Mark the starting node as visited
    visited[Source] = 1;
    while(!Q.empty()){
        Node = Q.front();
        Q.pop();

        // For the edges leaving from Node,
        // check if it can be added more flux
        for(int i = 0; i < AdList[Node].size(); i++){
            int NodeNext = AdList[Node][i];

            if( visited[NodeNext] != 1 && flux[Node][NodeNext] != cost[Node][NodeNext]){
                dad[NodeNext] = Node;

                // Check if the path reached the destination, and if it did
                // exit the function
                if(NodeNext == Destination)
                    return true;

                Q.push(NodeNext);
                visited[NodeNext] = 1;
            }
        }

        // For the edges coming into Node,
        // check if it can be added more flux
        for(int i = 0; i < AdInList[Node].size(); i++){
            int NodeNext = AdInList[Node][i];
            if( visited[NodeNext] != 1 && flux[Node][NodeNext] > 0){
                dad[NodeNext] = -Node;

                // Check if the path reached the destination, and if it did
                // exit the function
                if(NodeNext == Destination)
                    return true;

                Q.push(NodeNext);
                visited[NodeNext] = 1;
            }
        }
    }
    return false;
}

// Considering the left and the right set, two extra nodes will be added:
// -> source - has outer nodes to all nodes from the left set
// -> destination - all nodes from the right set will go into this new node
// EdmondsKarp starting from the source node, where each edge has the maximum capacity of 1

int main() {
    int NodeX, NodeY;

    ////////////////////////////
    /////// READING DATA ///////
    ////////////////////////////

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

    fin >> NodesL >> NodesR >> Edges;
    // + 2 -->  for the pseudo nodes: starting and ending
    Nodes = NodesL + NodesR + 2;

    // Resize adjacency lists
    AdjacencyList = new vector<int>[Nodes + 1];
    AdjacencyInnerList = new vector<int>[Nodes + 1];

    // Resize matrixs
    flux = new long* [Nodes + 1];
    cost = new long* [Nodes + 1];

    for(int i = 0; i <= Nodes; i++){
        flux[i] = new long [Nodes + 1];
        cost[i] = new long [Nodes + 1];
    }

    for(int i = 0; i < Edges; i++){
        fin >> NodeX >> NodeY;

        // In the problem, we need to transform the Node 1 from the right
        // set into 1 + NodesL, because we need to have a total of NodesR + NodesL nodes
        AdjacencyList[NodeX].push_back(NodeY + NodesL);
        AdjacencyInnerList[NodeY + NodesL].push_back(NodeX);

        // Initialize matrixs
        cost[NodeX][NodeY + NodesL] = 1;
        flux[NodeX][NodeY + NodesL] = 0;
    }

    fin.close();

    int source = Nodes - 1, destination = Nodes, dest, maxflow = 0;
    int *dad = new int[Nodes + 1], *visited = new int [Nodes + 1];

    // We add the nodes that leave the pseudo starting node
    // ---> they will go into the nodes from the left set
    for(int i = 1; i <= NodesL; i++){
        AdjacencyList[source].push_back(i);
        AdjacencyInnerList[i].push_back(source);

        // Initialize matrixs
        cost[source][i] = 1;
        flux[source][i] = 0;
    }

    // We add the nodes that go into the pseudo ending node
    // ---> they will come from the right set
    for(int i = NodesL + 1; i <= NodesL + NodesR; i++){
        AdjacencyList[i].push_back(destination);
        AdjacencyInnerList[destination].push_back(i);

        // Initialize matrixs
        cost[i][destination] = 1;
        flux[i][destination] = 0;
    }

    // While we can discover unsaturated path
    while(FindUnsaturatedPath(source, destination, Nodes, AdjacencyList, AdjacencyInnerList, flux, cost, dad, visited)){
        // Calculate the minimum rezidual capacity in the path that the
        // function has found
        long MRC = LONG_MAX;
        dest = destination;

        while(dest != source){
            // Edge leaving from dad
            if(dad[dest] >= 0){
                if( cost[dad[dest]][dest] - flux[dad[dest]][dest] < MRC)
                    MRC = cost[dad[dest]][dest] - flux[dad[dest]][dest];
                dest = dad[dest];
            } else{
                // Edge coming into dad
                if( flux[dest][-dad[dest]] < MRC)
                    MRC = flux[dest][-dad[dest]];
                dest = -dad[dest];
            }
        }
        dest = destination;
        while(dest != source){
            if(dad[dest] > 0){
                flux[dad[dest]][dest] += MRC;
                dest = dad[dest];
            } else{
                flux[dest][-dad[dest]] += MRC;
                dest = -dad[dest];
            }
        }
        maxflow += MRC;
    }

    fout << maxflow << endl;
    for(int i = 1; i <= NodesL; i++){
        for(int j = 0; j < AdjacencyList[i].size(); j++){
            if(flux[i][AdjacencyList[i][j]] == 1){
                fout << i << " " << int(AdjacencyList[i][j] % NodesL) << endl;
            }
        }
    }

    fout.close();

    return 0;
}