Pagini recente » Cod sursa (job #2866312) | Cod sursa (job #1797624) | Cod sursa (job #2194024) | Cod sursa (job #245375) | Cod sursa (job #1396030)
#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];
vector <int> paths;
int maxMatch = 0;
int root[2 * MAXV];
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() {
bool foundPath = false;
queue <int> q;
// push in q only the nodes from L
// the bfs finds all augmenting paths that end up at some unmatched node in R
for (int node = L; node > 0; -- node) {
if (match[node] == 0) { // if node is unmatched
father[node] = node; // it becomes an independent tree
dist[node] = 0; // its length is 0
root[node] = node; // the root of the tree is node
q.push(node); // and push it in q for expansion (follow the path)
} else { // if node is matched (i.e. belongs to an edge in the current M)
father[node] = -1; // initialisation
dist[node] = -1; // initialisation
root[node] = -1; // initialisation
}
}
// the unmatched node from R are not pushed into q,
// but they are marked to be later recognized as end of path
for (int node = L + R; node > L; -- node) {
if (match[node] == 0) { // if node is unmatched
father[node] = 0; // 0 means that node is an unmatched node in R
} else {
father[node] = -1; // initialisation
}
dist[node] = -1; // initialisation
root[node] = -1; // initialisation
}
for (int node; !q.empty(); q.pop()) {
node = q.front();
for (vector <int>::iterator it = G[node].begin(); it != G[node].end(); ++ it) {
// we need to create an alternating path,
// thus the edges we can follow are dependent on the parity of the distance to node
if ((match[*it] == node) == dist[node] % 2) {
if (father[*it] == -1) { // if *it was not expanded
father[*it] = node;
dist[*it] = dist[node] + 1;
root[*it] = root[node];
q.push(*it);
// if father[*it] != -1 then there are 2 cases
// first case father[*it] != 0, which means that *it belongs to some path already
// second case father[*it] == 0 which means we found and "end of path" node (in R)
// also there is no need to check for cycles
// e.g. L = {1, 2}, R = {1, 2}, E = {(1,1), (1,2), (2,1), (2,2)}
// why?
// say we have a path p, |p| = l and a cycle c which includes p
// then |c| > l (there is no equal because p is a path,
// to make p a cycle we need at least one more edge)
// by the definition of augmenting paths we also know that
// start(p) in L and end(p) in R
// because bfs finds the shortest paths
// p will be encountered before c;
// it the following if, *it (end(p)) is not pushed into q
// so the path is not followed anymore,
// thus the cycle c is never reached
} else if (father[*it] == 0) {
father[*it] = node;
dist[*it] = dist[node] + 1;
root[*it] = root[node];
foundPath = true;
// Hopcroft-Karp is to Edmonds-Blossom (on bipartite matching)
// as is
// Dinic to Edmonds-Karp (on max flow)
// instead of augmenting one path with one bfs
// we augment a maximal number of paths with the same bfs
// (maximal is not the maximum
// and it means as many paths as we can)
paths.push_back(*it);
}
}
}
}
return foundPath;
}
inline void bipartiteMatchingWithHopcroftKarp() {
for (bool existsAugmentingPath = bfs(); existsAugmentingPath; existsAugmentingPath = bfs()) {
for (vector <int>::iterator it = paths.begin(); it != paths.end(); ++ it) {
// by some lemma regarding Hopcroft-Karp
// all the paths to be augmented here are vertex-disjoint
// however, this implementation does not guarantee this
// (one more thing to take into consideration is that
// the length of the paths might be different,
// but they are all shortest paths to the respective end-node)
// because of the property that says
// all vertices in P (=paths) have degree <= 2
// we know that the paths cannot be vertex-disjoint only at the end nodes (start in L and end in R)
// for the end node in R, we deal with it in the bfs
// for the start node in L, we must check that
// after we have augmented some paths, the start node of the
// path we are trying to augment now (that is the root) is not matched
if (match[root[*it]]) continue;
for (int node = *it; node != father[node]; node = father[node]) {
if (dist[node] % 2 == 1) {
match[node] = father[node];
match[father[node]] = node;
}
}
maxMatch ++;
}
paths.clear();
}
}
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();
bipartiteMatchingWithHopcroftKarp();
printResult();
return 0;
}