Cod sursa(job #2967120)

Utilizator readyitzooDilirici Mihai readyitzoo Data 19 ianuarie 2023 02:04:48
Problema Cuplaj maxim in graf bipartit Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.71 kb
// Time Complexity: O(V * E^2) ( V = number of vertices, E = number of edges )
#include <iostream>
#include <fstream>
#include <list>
#include <vector>
#include <tuple>
#include <queue>

using namespace std;

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

// sizeLeft = number of nodes in the left part of the bipartite graph
// sizeRight = number of nodes in the right part of the bipartite graph
// edges = number of edges in the bipartite graph
int sizeLeft, sizeRight, edges;

// s is the source node and t is the sink node
int s, t;

// inRight[i] is true if the node i from the right part of the bipartite graph has at least one incoming edge
vector < bool > inRight;

// parent[i] is a pair (node, edge index) where node is the node from which node i was reached and edge index is the index of the edge in the adjacency list of node
vector < pair < int, int >> parent;

// nodesRight[i] is a pair (node, edge index) for each edge connecting a node from the right part of the bipartite graph to the sink node t
vector < pair < int, int >> nodesRight;

// adjList[i] is a list of pairs (node, (capacity, edge index)) for each edge connecting node i to another node
// capacity is the current capacity of the edge and edge index is the index of the edge in the adjacency list of the other node
vector < vector < pair < int, pair < int, int >>>> adjList;

// create an edge between nodes x and y with capacity 1
void createEdge(int x, int y) {
    // add an edge from x to y with capacity 1 and edge index adjList[y].size()
    adjList[x].push_back({y, {1,adjList[y].size()}});
    // add an edge from y to x with capacity 0 and edge index adjList[x].size() - 1
    adjList[y].push_back({x, {0,adjList[x].size() - 1}});

    // if y is the sink node t, add the edge to the list of edges connecting nodes from the right part of the bipartite graph to t
    if (y == t) {
        nodesRight.emplace_back(x, adjList[x].size() - 1);
    }
}

// breadth-first search to find augmenting paths
bool bfs() {
    // visited[i] is true if node i has been visited during the current search
    vector < bool > visited(t + 1);
    queue < int > q;

    // start the search at the source node s
    q.push(s);
    visited[s] = true;
    parent[s] = {-1, -1}; // the parent of s is not set

    // continue the search as long as there are nodes in the queue
    while (!q.empty()) {
        int firstInQueue = q.front();
        q.pop();

        // skip the sink node t because we don't want to find a path to it
        if (firstInQueue == t) {
            continue;
        }

        // consider each outgoing edge of the current node
        int i = 0;

        for (auto const& adjNode: adjList[firstInQueue]) {
            int capacity = adjNode.second.first; // capacity of the current edge
            int node = adjNode.first; // adjacent node

            // if the adjacent node has not been visited and the capacity of the current edge is greater than 0
            if (!visited[node] && capacity) {
                // set the parent of the adjacent node to be the current node and the index of the current edge
                parent[node] = {firstInQueue, i};
                // mark the adjacent node
                parent[node] = {firstInQueue, i};
                visited[node] = true;
                q.push(node);
            }

            ++i;
        }
    }

    return visited[t];
}

// Compute the maximum flow in the bipartite graph
long long int cuplaj() {
    long long int maxFlow = 0; // initialize the maximum flow to 0

    while (bfs()) {  // repeat as long as there are augmenting paths
        for (auto const& adjNode: nodesRight) {  // for each edge connecting a node from the right part of the bipartite graph to the sink t
            int currentFlow = 1;  // the flow along the current augmenting path is 1
            parent[t] = adjNode;  // set the parent of t to be the current node
            int y = t;  // start from the sink t

            // trace back the path from t to s
            while (parent[y].first != -1) {
                // find the node and the index of the edge in the adjacency list of the node
                int x = parent[y].first;
                int i = parent[y].second;
                // update the residual capacity of the edge
                adjList[x][i].second.first = 0;
                // update the current flow by the residual capacity of the edge
                currentFlow = min(currentFlow, adjList[y][adjList[x][i].second.second].second.first);
                y = x;
            }

            // update the maximum flow
            maxFlow += currentFlow;

            // trace back the path from t to s again and update the flow along the edges
            y = t;
            while (parent[y].first != -1) {
                int x = parent[y].first;
                int i = parent[y].second;
                // update the flow of the edge from x to y
                adjList[x][i].second.first -= currentFlow;
                // update the flow of the edge from y to x
                adjList[y][adjList[x][i].second.second].second.first += currentFlow;
                y = x;
            }
        }
    }

    return maxFlow;  // return the maximum flow

}

int main() {
    f >> sizeLeft >> sizeRight >> edges; // read the number of nodes in the left and right part of the bipartite graph and the number of edges

    t = sizeLeft + sizeRight + 1;
    inRight.resize(sizeRight + 1);
    parent.resize(t + 1);
    adjList.resize(t + 1);

    // create edges from the source s to the nodes in the left part of the bipartite graph
    for (int i = 1; i <= sizeLeft; ++i) {
        createEdge(s, i);
    }

    // create edges from the nodes in the right part of the bipartite graph to the sink t
    for (int i = 1; i <= edges; ++i) {
        int x, y;
        f >> x >> y;
        createEdge(x, sizeLeft + y);
        inRight[y] = true;
    }

    // create edges from the nodes in the left part of the bipartite graph to the nodes in the right part of the bipartite graph
    for (int i = 1; i <= sizeRight; ++i) {
        if (inRight[i]) {
            createEdge(sizeLeft + i, t);
        }
    }

    // compute the maximum flow
    g << cuplaj() << '\n';
    for (int i = 1; i <= sizeLeft; ++i) {
        // for each node in the left part of the bipartite graph, find the node in the right part of the bipartite graph to which it is connected
        for (auto const &node: adjList[i]) {
            int vertex, capacity;

            vertex = node.first;
            capacity = node.second.first;

            // if the node is in the right part of the bipartite graph and the edge from i to vertex is not in the residual graph
            if (vertex && capacity == 0 && vertex != t) {
                g << i << " " << vertex - sizeLeft << '\n';
            }
        }
    }
}