Pagini recente » Cod sursa (job #341099) | Cod sursa (job #2915183) | Cod sursa (job #326762) | Cod sursa (job #1139450) | Cod sursa (job #2961360)
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
#include <climits>
#include <stack>
#include <unordered_map>
using namespace std;
ifstream fin("cuplaj.in");
ofstream fout("cuplaj.int");
/*
* Algoritmul este prezentat in curs. Pasii sunt urmatorii:
* 1. Se adauga o sursa si un destinatie fictive
* 2. Se adauga muchiile de la sursa si destinatie la cele doua multimi de noduri
* 3. Se considrea acum fiecare muchie din graf ca avand capacitatea 1
* 4. Se aplica algoritmul lui Ford-Fulkerson
* 5. Se afiseaza numarul de muchii din multimea de muchii care au fost folosite
*/
// ---------------------- //
int n, m, e, s, d;
int total_nodes;
vector <vector<int>> graph;
vector <Edge> edges;
// ---------------------- //
// Construim o structura de date care ne va ajuta sa reprezentam un graf
struct Edge
{
// Pozitia ne va trebui la Ford-Fulkerson
int from, to, capacity, pozitie;
};
// Functia care adauga o muchie in graful rezidual
void addEdge (int x, int y)
{
// In lista de adiacenta o sa pastram indexul muchiei
int index = edges.size();
// Creem muchia
Edge e1 = {x, y, 1, index + 1};
// Adaugam muchia in lista de adiacenta
graph[y].push_back(index + 1);
edges.push_back(e1);
// Trebuie sa adaugam si muchia inversa pentru graful residual
Edge e2 = {y, x, 0, index};
graph[x].push_back(index);
}
// Folosim BFS pentru a determina daca exista un drum de la sursa la destinatie
// In Ford-Fulkerson vom folosi BFS pentru a determina daca exista un drum de la sursa la destinatie, care sa aiba capacitatea mai mare decat 0
// Asta inseamna ca mai putem adauga flux pe acel drum
// Vector de parinti pentru a putea parcurge arborele bfs
vector<int> tata;
// Vector unde tinem daca un nod a fost vizitat sau nu
vector<bool> vizitat;
int bfs ()
{
tata.clear();
tata.resize(total_nodes, -1);
vizitat.clear();
vizitat.resize(total_nodes, false);
// Vom porni intotdeauna de la sursa
vizitat[s] = true;
// Coada in care vom retine nodurile
queue<int> q;
q.push(s);
// Cat timp mai avem noduri in coada pargurgem graful
while (!q.empty())
{
int nod = q.front();
q.pop();
// Parcurgem muchiile din lista de adiacenta, care sunt
// retinute sub forma de index catre muchia din vectorul de muchii
for (auto index_muchie: graph(nod))
{
// Deschidem muchia
Edge e = edges[index_muchie];
// Daca nodul nu a fost vizitat si muchia are capacitatea mai mare decat 0
if (!vizitat[e.to] && e.capacity > 0)
{
// Marchez nodul ca vizitat
vizitat[e.to] = true;
// Marchez parintele nodului
tata[e.to] = index_muchie;
// Daca am ajuns la destinatie, atunci am gasit un drum
if (e.to == d)
return 1;
// Adaug nodul in coada
q.push(e.to);
}
}
}
if (vizitat[d])
return 1;
// Daca nu am gasit drum, atunci returnam 0
return 0;
}
// Functia care calculeaza fluxul maxim
// Ford-Fulkerson
int fordFulkerson ()
{
// Flux maxim
int flux = 0;
// Cat timp mai exista un drum de la sursa la destinatie
while (bfs())
{
for (auto index_muchie: graph[d])
{
if (vizitat[edges[index_muchie].to && edges[edges[index].pozitie].capacity > 0])
{
int capactiate = INT_MAX;
Edge e = edges[index_muchie];
tata[d] = e.pozitie;
int nod = d;
while (nod != s)
{
capactiate = min(capactiate, edges[tata[nod]].capacity);
nod = edges[tata[nod]].from;
}
nod = d;
// Actualizam fluxul, deci mai trebuie sa parcurgem drumul de la destinatie la sursa
while (nod != s)
{
edges[tata[nod]].capacity -= capactiate;
edges[edges[tata[nod]].pozitie].capacity += capactiate;
nod = edges[tata[nod]].from;
}
flux += capactiate;
}
}
}
return flux;
}
}
int main ()
{
fin >> n >> m >> e;
// Calculam numarul total de noduri
total_nodes = n + m + 2;
// Construim sursa si destinatia
// Stim ca nodurile incep de la 0 si sunt consecutive
s = 0;
d = total_nodes - 1;
// Construim graful
graph.resize(total_nodes);
// Citim muchiile
for (int i = 0; i < e; i++)
{
int x, y;
fin >> x >> y;
// Adaugam muchia in lista de adiacenta
addEdge(x, y + n);
}
// Adaugam muchiile de la sursa la nodurile din multimea A
for (int i = 1; i <= n; i++)
addEdge(s, i);
// Adaugam muchiile de la nodurile din multimea B la destinatie
for (int i = n + 1; i <= n + m; i++)
addEdge(i, d);
// Aplicam Ford-Fulkerson
fout << fordFulkerson() << endl;
for(int i = 0; i < edges.size(); i++)
{
if(edges[i].from < edges[i].to && edges[i].from != 0 && edges[i].to != d - 1 && edges[i].capacity == 0)
fout << edges[i].from << " " << edges[i].to - n << endl;
}
return 0;
}