Cod sursa(job #2698626)

Utilizator LittleWhoFeraru Mihail LittleWho Data 22 ianuarie 2021 16:33:38
Problema Cuplaj maxim in graf bipartit Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.26 kb
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef signed long long ll;
typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned char uchar;
template <typename T>
void printarray(T v[], uint n) {for(uint i = 0; i < n; i ++){cout << v[i] << " ";}cout << endl;}
template <typename T>
void printvector(vector<T> v){for (uint i = 0; i < v.size(); i ++){cout << v[i] << " ";}cout << endl;}
#define dbg(x) cout << #x " = " << x << " | ";
#define dbgnl(x) cout << #x " = " << x << endl;

const uint nmax = 10005 * 2;
const int INF = 2e9;
const char capacity = 1;

struct edge_t {
    int node;
    char flow, capacity;
    list<edge_t>::iterator opposite;
};
typedef list<edge_t>::iterator edge_iter;

list<edge_t> G[nmax];
edge_iter parent_edge[nmax];
int maxflow = 0;
int n, m, e;
int source, dest;
bitset<nmax> visited;

#define A_NODE(i) (i)
#define B_NODE(i) (i+n)

void read() {
    cin >> n >> m >> e;
    source = 0;
    dest = n + m + 1;
    for (int i = 0; i < e; i++) {
        int x, y;
        cin >> x >> y;

        G[A_NODE(x)].push_back({.node = B_NODE(y), .flow = 0, .capacity = 1});
        G[B_NODE(y)].push_back({.node = A_NODE(x), .flow = 0, .capacity = 0});

        // Link the edge going in the opposite direction
        G[A_NODE(x)].back().opposite = next(G[B_NODE(y)].end(), -1);
        G[B_NODE(y)].back().opposite = next(G[A_NODE(x)].end(), -1);
    }
    for (int i = 1; i <= n; i++) {
        G[source].push_back({.node = A_NODE(i), .flow = 0, .capacity = 1});
        G[A_NODE(i)].push_back({.node = source, .flow = 0, .capacity = 0});

        G[source].back().opposite = next(G[A_NODE(i)].end(), -1);
        G[A_NODE(i)].back().opposite = next(G[source].end(), -1);
    }
    for (int i = 1; i <= m; i++) {
        G[B_NODE(i)].push_back({.node = dest, .flow = 0, .capacity = 1});
        G[dest].push_back({.node = B_NODE(i), .flow = 0, .capacity = 0});

        G[B_NODE(i)].back().opposite = next(G[dest].end(), -1);
        G[dest].back().opposite = next(G[B_NODE(i)].end(), -1);
    }
}

bool bfs() {
    queue<int> q;
    q.push(source);
    visited[source] = true;

    while (!q.empty()) {
        int node = q.front();
        q.pop();

        if (node == dest) break;

        for (auto edge_it = G[node].begin(); edge_it != G[node].end(); ++edge_it) {
            if (!visited[edge_it->node] && edge_it->flow < edge_it->capacity) {
                visited[edge_it->node] = true;
                q.push(edge_it->node);
                parent_edge[edge_it->node] = edge_it;
            }
        }
    }

    if (visited[dest] == false) return false;

    for (auto dest_edge = G[dest].begin(); dest_edge != G[dest].end(); ++dest_edge) {
        // start from dest's neighours
        int cur_node = dest_edge->node;
        char minflow = dest_edge->opposite->capacity - dest_edge->opposite->flow;
        while (cur_node != source) {
            minflow = min(minflow, (char)(parent_edge[cur_node]->capacity - parent_edge[cur_node]->flow));

            cur_node = parent_edge[cur_node]->opposite->node;
        }

        // update the path
        cur_node = dest_edge->node;
        while (cur_node != source) {
            parent_edge[cur_node]->flow += minflow;
            parent_edge[cur_node]->opposite->flow -= minflow;
            cur_node = parent_edge[cur_node]->opposite->node;
        }

        // update the edge to the dest too
        dest_edge->flow -= minflow;
        dest_edge->opposite->flow += minflow;

        maxflow += minflow;
    }

    return true;
}

void solve() {
    bool retry = true;
    while(retry) {
        retry = bfs();
        visited.reset();
    }
}

void write() {
    cout << maxflow << "\n";

    for (auto edge: G[source]) {
        if (edge.flow == edge.capacity) {
            for (auto match: G[edge.node]) {
                if (match.flow == match.capacity && match.node != source) {
                    cout << (int)edge.node << " " << (int)(match.node-n) << "\n";
                }
            }
        }
    }
}

int main() {
    freopen("cuplaj.in", "r", stdin);
    freopen("cuplaj.out", "w", stdout);

    read();
    solve();
    write();

    return 0;
}