Cod sursa(job #2694015)

Utilizator nicu_ducalNicu Ducal nicu_ducal Data 7 ianuarie 2021 20:31:31
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.46 kb
#include <bits/stdc++.h>
using namespace std;

template <typename T> ostream& operator<<(ostream &os, const vector<T> &v) { os << '{'; string sep; for (const auto &x : v) os << sep << x, sep = ", "; return os << '}'; }
template <typename A, typename B> ostream& operator<<(ostream &os, const pair<A, B> &p) { return os << '(' << p.first << ", " << p.second << ')'; }
using i64 = long long int;

const int INF = INT_MAX, MOD = 1e9 + 7;
const double EPS = 1e-9, PI = acos(-1);
const int dx[] = {0, 0, 0, -1, 1, -1, 1, 1, -1};
const int dy[] = {0, -1, 1, 0, 0, -1, 1, -1, 1};


/// Undirected/directed graph (for directed delete a push_back from the addEdge
/// Algorithm: Kuhn's algorithm for bipartite matchings (O(NM) or O(N^3) worst case)
/// Hopcroft-Karp's algorithm for bipartite marchings (O(sqrt(N) * M))
struct Graph {
  vector<vector<int>> adj;
  vector<bool> marked;
  vector<int> parent, level, match, is_matched;
  int n, n1, n2, match_num = 0;

  Graph(int _n1 = 0, int _n2 = 0) {
    init(_n1, _n2);
  }

  void init(int _n1, int _n2) {
    n = _n1 + _n2;
    n1 = _n1, n2 = _n2;
    adj.resize(n1 + 1);
    marked.resize(n1 + 1, false);
    match.resize(n2 + 1, -1);
    is_matched.resize(n1 + 1, -1);
  }

  void addEdge(int u, int v) {
    adj[u].push_back(v);
    // adj[v].push_back(u);
  }

  bool KuhnDFS(int node) {
    if (marked[node]) return false;
    marked[node] = true;
    for (auto next: adj[node]) {
      if (match[next] == -1 or KuhnDFS(match[next])) {
        match[next] = node;
        return true;
      }
    }
    return false;
  }

  /// Really, is this TLE???
  void Kuhn() {
    /// Adding the arbitrary matching heuristic
    vector<bool> arbitrary_matched(n1 + 1, false);
    for (int node = 1; node <= n1; node++) {
      for (auto next: adj[node]) {
        if (match[next] == -1) {
          match_num++;
          match[next] = node;
          arbitrary_matched[node] = true;
          break;
        }
      }
    }

    for (int node = 1; node <= n1; node++) {
      if (arbitrary_matched[node]) continue;
      marked.assign(n1 + 1, false);
      if (KuhnDFS(node))
        match_num++;
    }
  };

  /// Hopcroft-Karp Algorithm (O(sqrt(N) * M))
  bool HopcroftKarpDFS(int node) {
    if (marked[node]) return false;
    marked[node] = true;
    for (auto next: adj[node]) {
      if (match[next] == -1 or HopcroftKarpDFS(match[next])) {
        is_matched[node] = next;
        match[next] = node;
        return true;
      }
    }
    return false;
  }

  /// Uses the same DFS approach as Kuhn, I think
  void HopcroftKarp() {
    bool good = true;
    while (good) {
      good = false;
      marked.assign(n1 + 1, false);
      for (int node = 1; node <= n1; node++) {
        if (is_matched[node] == -1) {
          good |= HopcroftKarpDFS(node);
        }
      }
    }

    for (int node = 1; node <= n2; node++) {
      if (match[node] != -1)
        match_num++;
    }
  }
};

int main() {
  ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
  /// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

  ifstream cin("cuplaj.in");
  ofstream cout("cuplaj.out");
  
  int N1, N2, M;
  cin >> N1 >> N2 >> M;
  Graph graph(N1, N2);
  for (int i = 0; i < M; i++) {
    int u, v;
    cin >> u >> v;
    graph.addEdge(u, v);
  }

  /// graph.Kuhn();
  graph.HopcroftKarp();

  cout << graph.match_num << "\n";
  for (int i = 1; i <= N2; i++) {
    if (graph.match[i] != -1) {
      cout << graph.match[i] << " " << i << "\n";
    }
  }

  return 0;
}