Cod sursa(job #2210239)

Utilizator mlc_oficialBoris Barca mlc_oficial Data 5 iunie 2018 22:43:14
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 6.95 kb
#include <cstdio>
#include <vector>
#include <cstddef>

namespace algo {

struct EmptyType {};

// Remember to Init() after adding the edges
template <typename EdgeAttributes = EmptyType>
class Graph {
 private:
  template <typename T> struct Range;

 public:
  explicit Graph(int n, int m = 0) : n_(n), offset_(n + 1) {
    if (m > 0) {
      in_.reserve(m);
    }
  }

  void AddEdge(int x, int y, const EdgeAttributes attr = EdgeAttributes()) {
    in_.emplace_back(x, y, attr);
  }

  virtual void AdditionalInit() {}

  void Init() {
    ReorderEdges();
    AdditionalInit();
  }

  size_t size() const {
    return (size_t)n_;
  }

  Range<int> operator[](const int u) {
    return Range<int>(&edges_[offset_[u]], &edges_[offset_[u + 1]]);
  }

  int node(const int edge_idx) const {
    return in_[edge_idx].to;
  }

  EdgeAttributes value(const int edge_idx) const {
    return in_[edge_idx];
  }

 protected:
  void ReorderEdges() {
    edges_.resize(in_.size());
    for (auto&& e : in_) {
      ++offset_[e.from];
    }
    for (int i = 1; i <= n_; ++i) {
      offset_[i] += offset_[i - 1];
    }
    for (size_t i = 0; i < in_.size(); ++i) {
      edges_[--offset_[in_[i].from]] = i;
    }
  }

  int n_;

 private:
  Graph() = delete;

  struct Edge : public EdgeAttributes {
    int from, to;
    Edge() {}
    Edge(int from_, int to_, const EdgeAttributes& attr)
        : EdgeAttributes(attr), from(from_), to(to_) {}
  };

  template <typename T>
  struct Range {
    struct Iterator {
      T& operator*() const                        { return *iter; }
      bool operator!=(const Iterator& rhs) const  { return iter != rhs.iter; }
      void operator++()                           { ++iter; }
      T* operator+(int i) const                   { return iter + i; }
      size_t operator-(const Iterator& rhs) const { return iter - rhs.iter; }
      T* iter;
    };

    Range(T* _first, T* _last) : first({_first}), last({_last}) {}
    T operator[](const int i) { return *(first + i); }
    size_t size() const       { return last - first; }
    Iterator& begin()         { return first; }
    Iterator& end()           { return last; }
    Iterator first, last;
  };

  std::vector<int> offset_, edges_;
  std::vector<Edge> in_;
};

}  // namespace algo

#include <functional>
#include <queue>

namespace algo {

template <typename EdgeAttributes=EmptyType>
class BipartiteGraph : public Graph<EdgeAttributes> {
 public:
  explicit BipartiteGraph(const int n, const int m = 0)
      : Graph<EmptyType>(n, m), side_(n), pair_(n, -1) {}

  void AdditionalInit() override {
    std::vector<bool> marked(this->n_);
    std::function<void(int, Side)> Dfs = [&](int node, Side where) {
      marked[node] = true;
      side_[node] = where;

      for (auto&& edge : (*this)[node]) {
        const int to = (*this).node(edge);
        if (not marked[to]) {
          Dfs(to, where == kLeft ? kRight : kLeft);
        }
      }
    };

    for (int i = 0; i < this->n_; ++i) {
      if (not marked[i]) {
        Dfs(i, kLeft);
      }
    }
  }

  int MaxMatching() {
    std::vector<int> dist(this->n_ + 1);
    std::function<bool(int)> PairUp = [&](int node) {
      if (node == this->n_) {
        return true;
      }

      for (auto&& e : (*this)[node]) {
        int adj = this->node(e);
        int to = pair_[adj];
        if (to == -1) {
          to = this->n_;
        }

        if (dist[to] != dist[node] + 1) {
          continue;
        }

        if (PairUp(to)) {
          pair_[node] = adj;
          pair_[adj] = node;
          return true;
        }
      }
      dist[node] = -1;
      return false;
    };

    std::function<bool()> Bfs = [&]() {
      std::queue<int> bfq;
      for (int i = 0; i < this->n_; ++i) {
        if (side_[i] != kLeft) {
          continue;
        }

        if (pair_[i] == -1) {
          dist[i] = 0;
          bfq.push(i);
        } else {
          dist[i] = -1;
        }
      }

      dist[this->n_] = -1;
      while (not bfq.empty()) {
        int node = bfq.front();
        bfq.pop();
        if (dist[this->n_] != -1 and dist[node] >= dist[this->n_]) {
          continue;
        }

        for (auto&& e : (*this)[node]) {
          int to = pair_[this->node(e)];
          if (to == -1) {
            to = this->n_;
          }

          if (dist[to] == -1) {
            dist[to] = dist[node] + 1;
            bfq.push(to);
          }
        }
      }
      return dist[this->n_] != -1;
    };

    int matching = 0;
    while (Bfs()) {
      for (int i = 0; i < this->n_; ++i) {
        if (side_[i] == kLeft and pair_[i] == -1 and PairUp(i)) {
          ++matching;
        }
      }
    }

    return matching;
  }

  std::vector<std::pair<int, int>> GetMatching() {
    int matching = MaxMatching();
    std::vector<std::pair<int, int>> solution;
    solution.reserve(matching);

    for (int i = 0; i < this->n_; ++i) {
      if (side_[i] == kLeft and pair_[i] != -1) {
        solution.emplace_back(i, pair_[i]);
      }
    }
    return solution;
  }

  std::vector<int> MinimumVertexCover() {  // = max_matching
    const int matching = MaxMatching();

    auto&& selected = SelectNodes();
    std::vector<int> solution;
    solution.reserve(matching);

    for (int i = 0; i < this->n_; ++i) {
      if (selected[i]) {
        solution.push_back(i);
      }
    }
    return solution;
  }

  std::vector<int> MaximumIndependentSet() {  // = n - max_matching
    const int matching = MaxMatching();

    auto&& selected = SelectNodes();
    std::vector<int> solution;
    solution.reserve(this->n_ - matching);

    for (int i = 0; i < this->n_; ++i) {
      if (not selected[i]) {
        solution.push_back(i);
      }
    }
    return solution;
  }

 private:
  enum Side {
    kLeft,
    kRight
  };

  std::vector<bool> SelectNodes() {
    std::vector<bool> selected(this->n_);
    for (int i = 0; i < this->n_; ++i) {
      if (side_[i] == kLeft and pair_[i] != -1) {
        selected[i] = true;
      }
    }

    std::function<void(int)> Cover = [&](int node) {
      for (auto&& edge : (*this)[node]) {
        const int to = (*this).node(edge);
        if (not selected[to]) {
          selected[to] = true;
          selected[pair_[to]] = false;
          Cover(pair_[to]);
        }
      }
    };

    for (int i = 0; i < this->n_; ++i) {
      if (side_[i] == kLeft and pair_[i] == -1) {
        Cover(i);
      }
    }
    return selected;
  }

  std::vector<Side> side_;
  std::vector<int> pair_;
};

}  // namespace algo

int main()
{
    freopen("cuplaj.in", "r", stdin);
    freopen("cuplaj.out", "w", stdout);
    int nl, nr, m;
    scanf("%d%d%d", &nl, &nr, &m);

    algo::BipartiteGraph<> graph(nl + nr, 2 * m);
    for (int i = 0; i < m; ++i) {
        int x, y;
        scanf("%d%d", &x, &y);
        --x; --y;
        y += nl;
        graph.AddEdge(x, y);
        graph.AddEdge(y, x);
    }

    graph.Init();

    auto matching = graph.GetMatching();

    printf("%d\n", matching.size());
    for (auto it : matching) {
        printf("%d %d\n", 1 + it.first, 1 - nl + it.second);
    }

}