Pagini recente » Cod sursa (job #1437307) | Cod sursa (job #1437646)
#include <fstream>
#include <vector>
using AdjLists = std::vector<std::vector<int>>;
constexpr auto NULL_VERTEX = -1;
///
// This is equivalent to a breath-first graph traversal in which we are trying
// to augment the matching with the path starting at vertex u.
//
// Augmenting the matching means finding an alternating path
// (formed by matched - unmatched - matched -.. nodes) and then, while returning
// from recursion, update the edges which are part of the matching accordingly.
///
bool
match(
int u,
const AdjLists &graph,
std::vector<int> &leftVertices,
std::vector<int> &rightVertices,
std::vector<bool> &visited)
{
// First check if this node has been previously visited. We want to augment
// the matching with disjoint shortest-paths.
if (visited[u])
return false;
visited[u] = true;
// Try to match this node with a node from the right side which is not
// matched.
for (auto &v : graph[u])
if (rightVertices[v] == NULL_VERTEX) {
leftVertices[u] = v;
rightVertices[v] = u;
return true;
}
// If such a node does not exist, try to match the nodes each of this
// node's neighbors is already matched to with other nodes than v's
// neighbors the intent to match u and v in the next iteration step.
for (auto &v : graph[u])
if (match(rightVertices[v], graph, leftVertices, rightVertices,
visited)) {
leftVertices[u] = v;
rightVertices[v] = u;
return true;
}
return false;
}
int main()
{
std::ios::sync_with_stdio(false);
std::ifstream fin{"cuplaj.in"};
std::ofstream fout{"cuplaj.out"};
int L, R, M;
fin >> L >> R >> M;
AdjLists graph(L);
for (auto i = 0; i < M; ++i) {
int x, y;
fin >> x >> y;
graph[x - 1].emplace_back(y - 1);
}
// By default all vertices are matched to the null vertex.
std::vector<int> leftVertices(L, NULL_VERTEX);
std::vector<int> rightVertices(R, NULL_VERTEX);
std::vector<bool> visited(graph.size());
bool changed;
// This is done sqrt(V) times.
do {
changed = false;
std::fill(visited.begin(), visited.end(), false);
for (auto i = 0u; i < graph.size(); ++i)
if (leftVertices[i] == NULL_VERTEX)
changed = changed || match(i, graph, leftVertices,
rightVertices, visited);
} while (changed);
// Trivial step: reconstruct the matching.
//
// First, count its size.
auto matching = 0;
for (auto i = 0u; i < graph.size(); ++i)
if (leftVertices[i] != NULL_VERTEX)
++matching;
// Then print all the edges it contains.
fout << matching << '\n';
for (auto i = 0u; i < graph.size(); ++i)
if (leftVertices[i] != NULL_VERTEX)
fout << i + 1 << ' ' << leftVertices[i] + 1 << '\n';
return 0;
}