Pagini recente » Cod sursa (job #633852) | Cod sursa (job #1931138) | Cod sursa (job #2227736) | Cod sursa (job #384005) | Cod sursa (job #1395700)
#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];
bool vertexInF[2 * MAXV];
int dist[2 *MAXV];
int match[2 * MAXV];
bool vertexMarked[2 * MAXV];
int father[2 * MAXV];
int firstPath, secondPath;
int maxMatch = 0;
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 findAugmentingPath() {
queue <int> qF; // qF contains all the vertices that are added in F, in the order they appear
for (int node = L + R; node > 0; -- node) {
if (match[node] == 0) { // if node is unmatched
qF.push(node);
vertexInF[node] = true;
dist[node] = 0;
} else { // if node is matched
vertexInF[node] = false;
dist[node] = -1; // -1 is used to enforce that node is not in F
}
vertexMarked[node] = false; // each vertex can be processed only once
father[node] = -1;
}
for (int node = qF.front(); !qF.empty(); node = qF.front()) {
qF.pop();
if (dist[node] % 2) continue;
for (vector <int>::iterator it = G[node].begin(); it != G[node].end(); ++ it) {
// check if edge is unmarked i.e. not used already
// because we are using a bipartite graph
// we need only to check that we are not going back
// on the edge that ended up on node
if (*it != father[node]) {
if (match[*it] != 0) { // *it is present on some edge of M i.e. *it not in F
// root(node) ~> node -> *it -> match[*it]
dist[match[*it]] = dist[node] + 2;
dist[*it] = dist[node] + 1;
father[match[*it]] = *it;
father[*it] = node;
if (vertexMarked[*it] == false) qF.push(*it);
if (vertexMarked[match[*it]] == false) qF.push(match[*it]);
} else if (dist[*it] % 2 == 0) {
// the path is root(node) ~> node -> *it ~> root(*it)
// we can reconstruct the path using the array father
// but it is split (due to the way father is defined)
// into root(node) ~> node and root(*it) ~> *it
firstPath = node;
secondPath = *it;
return true;
}
}
}
vertexMarked[node] = true;
}
return false;
}
inline void bipartiteMatchingWithEdmondsBlossom() {
for (int node = L + R; node > 0; -- node) {
match[node] = 0;
}
for (bool isPath = findAugmentingPath(); isPath; isPath = findAugmentingPath()) {
match[firstPath] = secondPath;
match[secondPath] = firstPath;
if (father[firstPath] != -1) {
for (int node = father[firstPath]; node != -1; node = father[father[node]]) {
match[node] = father[node];
match[father[node]] = node;
}
}
if (father[secondPath] != -1) {
for (int node = father[secondPath]; node != -1; node = father[father[node]]) {
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;
}