Cod sursa(job #3298706)

Utilizator nstefanNeagu Stefan nstefan Data 31 mai 2025 23:33:27
Problema Cuplaj maxim in graf bipartit Scor 28
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.31 kb
#include <bits/stdc++.h>
#define int long long
#define ld long double
using namespace std;

/*
 * Usage:
 Dinic<5010> dinic;
 int N; int M; cin >> N >> M;
 dinic.setup(1, N);
 for (int i = 0; i < M; i++) {
   int u, v, cap; cin >> u >> v >> cap;
   dinic.add_edge(u, v, cap);
 }
 cout << dinic.max_flow();
 */
template<int N>
struct Dinic {
private:
  struct Edge {
    int from; int to;
    int flow; int capacity;
    Edge(int a, int b, int c, int d) : from(a), to(b), flow(c), capacity(d) {}
    int remainingCapacity() const { return capacity - flow; }
  };
  int level[N], source, sink, next[N];
  vector<int> adj[N];
  vector<Edge> edges;
public:
  void setup(int source, int sink) { this->source = source; this->sink = sink; }
  void add_edge(int u, int v, int cap) {
    adj[u].emplace_back(edges.size());
    edges.emplace_back(u, v, 0, cap);
    adj[v].emplace_back(edges.size());
    edges.emplace_back(v, u, 0, 0);
  }
  bool do_levels() {
    memset(level, 0, sizeof(level));
    level[source] = 1;
    deque<int> dq; dq.emplace_back(source);

    while (!dq.empty()) {
      int curNode = dq.front(); dq.pop_front();
      for (auto edgeIndex : adj[curNode]) {
        const auto& edge = edges[edgeIndex];
        if (level[edge.to] == 0 && edge.remainingCapacity() > 0) {
          level[edge.to] = level[edge.from] + 1;
          dq.emplace_back(edge.to);
        }
      }
    }

    return level[sink] != 0;
  }
  int push_flow(int curNode, int flow) {
    if (curNode == sink) return flow;
    for (int& edgeOrder = next[curNode]; edgeOrder < adj[curNode].size(); edgeOrder++) {
      int edgeIndex = adj[curNode][edgeOrder];
      const auto& edge = edges[edgeIndex];
      if (level[edge.from] + 1 == level[edge.to] && edge.remainingCapacity() > 0) {
        int f = push_flow(edge.to, min(flow, edge.remainingCapacity()));
        if (f > 0) {
          edges[edgeIndex].flow += f;
          edges[edgeIndex ^ 1].flow -= f;
          return f;
        }
      }
    }
    return 0;
  }
  int max_flow() {
    int ans = 0;
    while (do_levels()) {
      memset(next, 0, sizeof(next));
      while (long long flow = push_flow(source, LONG_MAX)) {
        ans += flow;
      }
    }
    return ans;
  }
};

// Inspired by: https://infoarena.ro/job_detail/3297319?action=view-source

int L, R, M;
int p[10'010];
bool viz[10'010];
vector<int> adj[10'010];

bool pair_up(int node) {
  if (viz[node]) return false;
  viz[node] = true;

  for (auto neigh : adj[node]) {
    if (!p[neigh] || pair_up(p[neigh])) {
      p[node] = neigh;
      p[neigh] = node;
      return true;
    }
  }

  return false;
}

int32_t main() {
  cin.tie(0)->sync_with_stdio(0);
#ifdef N257
freopen("input.txt", "r", stdin);
#else
freopen("cuplaj.in", "r", stdin);
freopen("cuplaj.out", "w", stdout);
#endif

  // Setup the graph
  cin >> L >> R >> M;
  for (int i = 0; i < M; i++) {
    int leftNode, rightNode; cin >> leftNode >> rightNode;
    rightNode += L;
    adj[leftNode].emplace_back(rightNode);
    // adj[rightNode].emplace_back(leftNode);
  }

  bool dai = true;
  int cnt = 0;
  while ( dai ) {
    dai = false;
    memset(viz, 0, sizeof(viz));

    for (int i = 1; i <= L; i++) {
      if (!p[i] && pair_up(i)) {
        dai = true;
        cnt++;
      }
    }
  }

  cout << cnt << '\n';
  for (int i = 1; i <= L; i++) {
    if (p[i])
      cout << i << ' ' << p[i] << '\n';
  }
}