Cod sursa(job #2587093)

Utilizator gabrielinelusGabriel-Robert Inelus gabrielinelus Data 21 martie 2020 23:53:22
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.21 kb
#include <cstdio>
#include <vector>
#include <bitset>

using namespace std;
vector<vector<int>> Graph; // Graph[i] = the neighbours of i on the right (i being on the left)
vector<int> Left; // Left[i] = who's i's match on the left (i being on the right)
vector<int> Right; // Right[i] = who's i's match on the right (i being on the left)
bitset<10005> used; // used[i] = true <=> i is part of an alternating path in the current run

bool findMatch(int k)
{
  if (used[k])
    return false; // k was already part of an alternating path in this run

  used[k] = true; 

  for (auto v : Graph[k]) 
    if (Left[v] == -1) {
      Right[k] = v;
      Left[v] = k;
      return true;
    }

  /**
     There is no free neighbour for k, but if we can find a match
     for the Left[v] which is not v, without touching the alternating
     path that we are building, then we can link k to v.
   */

  for (auto v: Graph[k])
    if (findMatch(Left[v])) {
      Right[k] = v;
      Left[v] = k;
      return true;
    }

  // We failed to extend the alternating path.
  return false;
}

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

  int L, R, M;
  scanf("%d%d%d", &L, &R, &M);

  Graph.resize(L);
  Left.resize(R);
  Right.resize(L);

  fill(Left.begin(), Left.end(), -1);
  fill(Right.begin(), Right.end(), -1);
  
  for (int i = 0; i < M; ++i) {
    int l, r;
    scanf("%d%d", &l, &r);
    --l;
    --r;
    Graph[l].emplace_back(r);
  }

  /**
     Every pair in the maximal match has a node on the left side. Thus,
     we equivalently try to maximize the number of nodes on the left that
     are part of a match using alternating paths.
  */

  int matches = 0;
  bool madeProgress = true;
  while (madeProgress) {
    madeProgress = false;
    used = 0;
    /**
       For each node that does not have a match already, we try to find it match.
       If successful, then we increased the number nodes on the left that are 
       part of a match.
     */
    for (int i = 0; i < L; ++i)
      if (Right[i] == -1 && findMatch(i)) {
	++matches;
	madeProgress = true;
      }
  }
  
  printf("%d\n", matches);
  for (int i = 0; i < L; ++i)
    if (Right[i] != -1)
      printf("%d %d\n", i + 1, Right[i] + 1);
	
  return 0;
}