Cod sursa(job #3042204)

Utilizator ptudortudor P ptudor Data 4 aprilie 2023 19:02:48
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.23 kb
#include <bits/stdc++.h>
#define int long long
using namespace std;

//#define LOCAL

#ifdef LOCAL
ifstream in("in.in");
ofstream out("out.out");
#else
ifstream in("cuplaj.in");
ofstream out("cuplaj.out");
#endif

const int inf = (1LL << 61);

namespace MaxFlow {
    struct Edge {
        int to,rev,cap,flow;
    };
    vector<Edge> edges;
    vector<vector<int>> g;
    vector<int> parent,dis,parentEdge,last_edge;
    void init(int n) {
        g.resize(n + 1);
        dis.resize(n + 1);
        parent.resize(n +1);
        parentEdge.resize(n+1);
        last_edge.resize(n+1);
    }
    void add_edge(int u, int v, int cap) {
        //cout << "add edge " << u << " " << v << "\n";
        g[u].push_back(edges.size());
        edges.push_back(Edge{v,(int)edges.size(),cap,0});
        g[v].push_back(edges.size());
        edges.push_back(Edge{u,(int)edges.size() - 1, 0, 0});
    }

    int dif(const Edge &v) {
        return v.cap - v.flow;
    }

    bool bfs(int s, int t) {
        fill(dis.begin(),dis.end(),inf);
        fill(parent.begin(),parent.end(),-1);
        queue<int> q;
        dis[s] = 0;
        q.push(s);
        while(!q.empty()) {
            int node = q.front();
            q.pop();
            for (auto e : g[node]) {
                int to = edges[e].to;
                if (dis[node] + 1 < dis[to] && dif(edges[e])) {
                    dis[to] = dis[node] + 1;
                    parent[to] = node;
                    parentEdge[to] = e;///the edge that got us here
                    q.push(to);
                }
            }
        }
        return (parent[t] != -1);
    }

    int push_flow(int node, int t, int flow) {
        if (node == t) {
            return flow; /// we can push as much flow as we care from here
        }
        for (int &i = last_edge[node]; i < g[node].size(); i++) {
            int free = dif(edges[g[node][i]]);
            if (free == 0) continue;

            int k = edges[g[node][i]].to;
            if (dis[k] != dis[node] + 1) {
                continue;
            }
            int pushed_flow = push_flow(k,t,min(flow,free));
            if (pushed_flow > 0) { // we can actually push flow yay
                edges[g[node][i]].flow += pushed_flow;
                edges[g[node][i]^1].flow -= pushed_flow;
                return pushed_flow;
            }
        }
        return 0;
    }

    int get_flow(int s, int t) {
        int total_flow = 0;
        while(bfs(s,t)) {
            fill(last_edge.begin(), last_edge.end(),0);
            while(int p = push_flow(s,t,inf)) {
                total_flow += p;
            }
        }
        return total_flow;
    }
}

int n,m,e;
int32_t main() {
    in >> n  >> m >> e;
    MaxFlow::init(n + m + 1);
    for (int i = 1; i <= n; i++) {
        MaxFlow::add_edge(0,i,1);
    }
    for (int i = 1; i <=m; i++) {
        MaxFlow::add_edge(i + n, n + m + 1,1);
    }
    for (int i = 1; i <= e; i++) {
        int u,v;
        in >> u >> v;
        MaxFlow::add_edge(u,v + n,1);
    }
    
    out << MaxFlow::get_flow(0,n+m+1) << "\n";
    for  (int i = 1; i <= n; i++) {
        for (auto k : MaxFlow::g[i]) {
            if (MaxFlow::edges[k].flow > 0) {
                out << i << " " << -n + MaxFlow::edges[k].to << "\n";
            }
        }
    }
}