Pagini recente » Cod sursa (job #522889) | Cod sursa (job #2575282) | Cod sursa (job #1471964) | Cod sursa (job #661388) | Cod sursa (job #1395835)
#include <fstream>
#include <vector>
#include <queue>
#define MAXV 10001
using namespace std;
ifstream in("cuplaj.in");
ofstream out("cuplaj.out");
int L, R, E;
vector <int> G[2 * MAXV];
int match[2 * MAXV];
int father[2 * MAXV];
int dist[2 * MAXV];
int maxMatch = 0;
int firstPath, secondPath;
inline void readAndBuild() {
in >> L >> R >> E;
int x, y;
for (int e = 0; e < E; ++ e) {
in >> x >> y;
G[x].push_back(y + L);
G[y + L].push_back(x);
}
}
inline bool bfs() {
queue <int> q;
for (int node = L + R; node > 0; -- node) {
if (match[node] == 0) { // if node is an unmatched vertex
father[node] = node; // can also mean node has been pushed in q
dist[node] = 0;
q.push(node);
} else {
father[node] = -1; // not used
dist[node] = -1; // not used
}
}
// when q is empty, q.front() throws exception
// this loop avoids the case above
for (int node; !q.empty(); q.pop()) {
node = q.front();
for (vector <int>::iterator it = G[node].begin(); it != G[node].end(); ++ it) {
// if dist[node] is even then we need edges that are not in M
// if dist[node] is odd then we need edges that are in M
// the vertex *it can be in M and at the same time edge (node, *it) not in M
// the "if" tests if the edge (node, *it) has the type we want
if ((match[*it] == node) == dist[node] % 2) {
if (father[*it] == -1) { // if *it was never pushed in q, then it means we can follow the path
father[*it] = node;
dist[*it] = dist[node] + 1;
q.push(*it);
// if *it was pushed in q then we know for sure that
// there is a path root(*it) ~> *it (given by the array father)
// we already have the path root(node) ~> node
// the second condition is that the lengths of these 2 paths have the same parity
// i.e. the edges (father[node], node) and (father[*it], *it) have the same type
// so that in the end we can build an alternating path
} else if (dist[*it] % 2 == dist[node] % 2) {
firstPath = node;
secondPath = *it;
return true;
}
}
}
}
return false;
}
inline void bipartiteMatchingWithEdmondsBlossom() {
for (int existsAugmentingPath = bfs(); existsAugmentingPath; existsAugmentingPath = bfs()) {
// say last node in firstPath is x (=firstPath by implementation)
// and last node in secondPath is y
// then the edge (x, y) can be either in M or in E-M
// if it is in M then we do nothing
// (we are allowed to take no action, because the matching is changed in the other if branch)
// if it is in E-M then we add it to the matching
// parity = 0 means E-M edge
// parity = 1 means M edge
int parity = dist[firstPath] % 2;
if (parity == 0) {
match[firstPath] = secondPath;
match[secondPath] = firstPath;
}
// go up the firstPath and change the matching
for (int node = firstPath, sw = parity; node != father[node]; node = father[node], sw = 1 - sw) {
if (sw == 1) {
match[node] = father[node];
match[father[node]] = node;
}
}
// go up the secondPath and change the matching
for (int node = secondPath, sw = parity; node != father[node]; node = father[node], sw = 1 - sw) {
if (sw == 1) {
match[node] = father[node];
match[father[node]] = node;
}
}
maxMatch ++;
}
}
inline void printResult() {
out << maxMatch << '\n';
for (int i = 1; i <= L; ++ i)
if (match[i]) {
out << i << ' ' << match[i] - L << '\n';
}
}
int main() {
readAndBuild();
bipartiteMatchingWithEdmondsBlossom();
printResult();
return 0;
}