Pagini recente » Cod sursa (job #848014) | Cod sursa (job #1065621) | Cod sursa (job #2207773) | Cod sursa (job #1083092) | Cod sursa (job #2210239)
#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);
}
}