Pagini recente » Cod sursa (job #3291469) | Cod sursa (job #3293369) | Cod sursa (job #3292971) | Cod sursa (job #3292976) | Cod sursa (job #3289621)
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <limits>
using namespace std;
// Reprezintă "infinitul" ca o valoare foarte mare.
const int INF = numeric_limits<int>::max();
// Variabile globale pentru dimensiunile grafului și numărul de muchii.
// leftCount - numărul de noduri din mulțimea stângă (L)
// rightCount - numărul de noduri din mulțimea dreaptă (R)
// edgeCount - numărul total de muchii între L și R
int leftCount, rightCount, edgeCount;
// leftAdj: pentru fiecare nod din L (indexat de la 1 la leftCount),
// se păstrează o listă cu vecinii din R (nodurile la care este conectat).
vector<vector<int>> leftAdj;
// distanceLeft: vectorul care va reține "distanța" (nivelul) fiecărui nod din L,
// calculată în etapa BFS (Breadth-First Search) pentru a construi graful nivelat.
vector<int> distanceLeft;
// pairLeft și pairRight: vectorii care păstrează cuplajul curent.
// pairLeft[u] este nodul din R cu care este cuplat nodul u din L (0 dacă nu este cuplat).
// pairRight[v] este nodul din L cu care este cuplat nodul v din R (0 dacă nu este cuplat).
vector<int> pairLeft, pairRight;
//
// --- Funcția BFS ---
//
// Scopul acestei funcții este de a construi un graf nivelat începând
// de la toate nodurile libere (necuplate) din L. Pentru fiecare nod din L
// se calculează "distanța" (nivelul) de la un nod liber. Această informație
// este esențială pentru ca în etapa DFS să căutăm doar drumuri care respectă
// această structură (trecerea de la nivelul d la nivelul d+1).
//
bool bfs() {
queue<int> q;
// Inițializare: pentru fiecare nod din L, dacă este necuplat,
// setăm distanța la 0 și îl adăugăm în coadă.
for (int leftNode = 1; leftNode <= leftCount; leftNode++) {
if (pairLeft[leftNode] == 0) {
distanceLeft[leftNode] = 0;
q.push(leftNode);
} else {
// Dacă nodul este cuplat, nu-l considerăm în această etapă.
distanceLeft[leftNode] = INF;
}
}
// Setăm distanța pentru nodul "dummy" 0 la INF.
// Nodul 0 reprezintă un nod fictiv ce marchează sfârșitul drumurilor.
distanceLeft[0] = INF;
// Parcurgem în lățime (BFS) graful nivelat.
while (!q.empty()) {
int leftNode = q.front();
q.pop();
// Dacă nodul curent nu este nodul dummy, explorăm vecinii săi.
// Pentru fiecare nod din R adiacent nodului leftNode
for (int rightNode : leftAdj[leftNode]) {
// Verificăm cu ce nod din L este cuplat rightNode
int pairedLeft = pairRight[rightNode];
// Dacă rightNode este liber, înseamnă că am ajuns la capătul unui drum augmentant.
if (pairedLeft == 0) {
distanceLeft[0] = distanceLeft[leftNode] + 1;
}
// Dacă rightNode este cuplat și nodul din L cu care este cuplat nu a fost vizitat,
// actualizăm distanța și îl adăugăm în coadă.
else if (distanceLeft[pairedLeft] == INF) {
distanceLeft[pairedLeft] = distanceLeft[leftNode] + 1;
q.push(pairedLeft);
}
}
}
// Dacă distanța pentru nodul dummy s-a schimbat, înseamnă că există cel puțin un drum augmentant.
return distanceLeft[0] != INF;
}
//
// --- Funcția DFS ---
//
// Această funcție încearcă să găsească un drum augmentant în graful nivelat,
// pornind de la un nod din L. Se respectă nivelurile calculate în etapa BFS,
// adică se merge de la un nod la un vecin care se află la nivelul curent + 1.
// Dacă se găsește un drum care duce la un nod liber (nod dummy 0), se actualizează
// cuplajele (pairLeft și pairRight) de-a lungul drumului.
//
bool dfs(int leftNode) {
// Parcurgem fiecare vecin din R al nodului leftNode
for (int rightNode : leftAdj[leftNode]) {
int pairedLeft = pairRight[rightNode];
// Dacă rightNode este liber sau dacă putem continua drumul augmentant
// de la nodul din L cu care este cuplat rightNode, respectând nivelul,
// atunci actualizăm cuplajul.
if (pairedLeft == 0 || (distanceLeft[pairedLeft] == distanceLeft[leftNode] + 1 && dfs(pairedLeft))) {
pairLeft[leftNode] = rightNode;
pairRight[rightNode] = leftNode;
return true;
}
}
// Dacă nu se găsește niciun drum augmentant pornind din leftNode,
// marcăm nodul cu INF pentru a nu-l reexamina.
distanceLeft[leftNode] = INF;
return false;
}
//
// --- Funcția hopcroftKarp ---
//
// Funcția principală care găsește cuplajul maxim.
// Se repetă alternanța dintre construcția grafului nivelat (BFS)
// și căutarea drumurilor augmentante (DFS). Pentru fiecare drum găsit,
// se mărește numărul total de cuplaje.
//
int hopcroftKarp() {
int matching = 0;
// Cât timp există drumuri augmentante (BFS returnează true),
// încercăm să le găsim cu DFS.
while (bfs()) {
// Pentru fiecare nod din L necuplat, încercăm să găsim un drum augmentant.
for (int leftNode = 1; leftNode <= leftCount; leftNode++) {
if (pairLeft[leftNode] == 0 && dfs(leftNode))
matching++;
}
}
return matching;
}
//
// --- Funcția main ---
//
// Aceasta citește graful din fișierul "cuplaj.in", inițializează variabilele necesare,
// apelează algoritmul Hopcroft-Karp pentru a calcula cuplajul maxim și scrie rezultatul în "cuplaj.out".
//
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
ifstream fin("cuplaj.in");
ofstream fout("cuplaj.out");
if (!fin || !fout) {
cerr << "Error opening input/output files!" << endl;
return 1;
}
// Citim numărul de noduri din L, din R și numărul de muchii
fin >> leftCount >> rightCount >> edgeCount;
// Inițializăm lista de adiacență pentru nodurile din L
leftAdj.resize(leftCount + 1);
// Inițializăm vectorii de cuplaje cu 0 (nodurile sunt inițial necuplate)
pairLeft.assign(leftCount + 1, 0);
pairRight.assign(rightCount + 1, 0);
// Inițializăm vectorul de distanțe cu INF
distanceLeft.assign(leftCount + 1, INF);
// Citim fiecare muchie și construim lista de adiacență.
// Fiecare muchie este dată printr-un nod u din L și un nod v din R.
for (int i = 0; i < edgeCount; i++) {
int u, v;
fin >> u >> v;
if (u >= 1 && u <= leftCount && v >= 1 && v <= rightCount)
leftAdj[u].push_back(v);
}
// Calculăm cuplajul maxim folosind algoritmul Hopcroft-Karp.
int maxMatching = hopcroftKarp();
// Scriem numărul maxim de cuplaje și apoi fiecare pereche (u din L, v din R)
fout << maxMatching << "\n";
for (int leftNode = 1; leftNode <= leftCount; leftNode++) {
if (pairLeft[leftNode] != 0)
fout << leftNode << " " << pairLeft[leftNode] << "\n";
}
fin.close();
fout.close();
return 0;
}