Pagini recente » Cod sursa (job #2731520) | Cod sursa (job #1233643) | Cod sursa (job #1640095) | Cod sursa (job #1340976) | Cod sursa (job #2962382)
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
#include <climits>
using namespace std;
// ifstream fin("input.txt");
// ofstream fout("output.txt");
// Cum am gandit:
// Din suportul de curs avem o serie de pasi pentru determinarea cuplajul maxim
// cuplajul maxim fiind in esenta nr maxim de muchii (un varf din left si un varf din right) care nu se intersecteaza/suprapun la capete
// a relatied de 1 la 1 fara suprapunere
// il putem afla prin flux maxim adaugand o sursa si o destinatie la multimile left si right de noduri
// adaugam muchiile din sursa si destinatie in relatie cu cele doua multimi
// iar fiecare muchie are capacitatea 1
// aplicam alg de flux maxim Ford
// fluxul maxim va da cardinalitatea cuplajului maxim
// iar muchiile saturate din "miez" (left si right cu propr de cuplaj maxim) var fi muchiile ce tr afisate
// am aplicat logica din suportul de curs pe Ford cu updatare de fluxuri
struct Edge
{
int sursa, destinatie, capacitate, pozitie; // pozitia ma ajuta sa accesez muchia ulterior
};
int n, m, e, s, d;
int nr_noduri;
vector<vector<int>> adj_indici; //in lista de adiacenta o sa pastram indexul muchiei
vector<Edge> edges;
void addEdge (int a, int b)
{
// In lista de adiacenta o sa pastram indexul muchiei
int index = (int) edges.size();
// muchiile create de capacitate 1
Edge m_1 = {a, b, 1, index + 1};
//lista de adiacentta a muchiilor sub forma de indici
adj_indici[b].push_back(index + 1);
edges.push_back(m_1);
//muchiile inverse ce vor fi folosite la graful rezidual, atentie sa pun capacitate 0 aici
Edge m_2 = {b, a, 0, index};
adj_indici[a].push_back(index);
edges.push_back(m_2);
}
// Aplicam BFS pt a determina daca exista un path de la sursa la destinatie,
// cu focus pe acele drumuri cu capc reziduala >0 (in acest sens mai putem adauga flux)
vector<int> parinte;
vector<int> vizitat;
bool bfs_cuplaj()
{
// puteam si cu memset(vazut, 0, sizeof(vazut));
parinte.clear();
parinte.resize(nr_noduri);
vizitat.clear();
vizitat.resize(nr_noduri, 0);
// Vom porni intotdeauna de la sursa
vizitat[s] = 1;
// Coada in care vom retine nodurile
queue<int> q_bfs;
q_bfs.push(s); // coada specifica BFS-ului
// parcurg pentru gasirea de path cu ajutorul cozii de bfs
while (!q_bfs.empty())
{
int nod = q_bfs.front();
q_bfs.pop();
if (nod != d) // daca nu am atins destinatia
for (auto index_muchie: adj_indici[nod])
{
Edge ed_curent = edges[index_muchie]; // // accesez informatiile legate de acea muchie cu ajutorul structurii
// nevizitare a nodului destinatie din muchia in cauza si nesaturare pe ea pt a coontinua pe acest path
if (!vizitat[ed_curent.destinatie] && ed_curent.capacitate > 0)
{
vizitat[ed_curent.destinatie] = 1; // este vazut si marcat
parinte[ed_curent.destinatie] = index_muchie; // preiau parintele ca pozitie
q_bfs.push(ed_curent.destinatie); // adaugam nodul la coada bfs
}
}
}
return vizitat[d]; // mi-a gasit path pe care sa fac update de flux
}
int fluxMaxim ()
{
int flux_max = 0;
// cat timp mai avem un drum de la sursa la destinatie
while (bfs_cuplaj())
{
for (auto index_muchie: adj_indici[d])
{
// verific capacitatea si destinatia la nivel de muchie
// daca este nesaturata o preiau mai departe si actualizez parintele destinatiei
// verific in esenta de la o destinatie la sursa, in sens invers
if (vizitat[edges[index_muchie].destinatie] &&
edges[edges[index_muchie].pozitie].capacitate > 0)
{
int flux = INT_MAX;
Edge ed_curent = edges[index_muchie]; // merg de la edge-ul curent si asociez parintii prin index
parinte[d] = ed_curent.pozitie;
int nod = d;
while (nod != s)
{
int prev = parinte[nod];
// partea de aflarea a minimului folosit pt augumentare
flux = min(flux, edges[prev].capacitate);
nod = edges[prev].sursa;
}
// partea de actualizare a fluxului per muchii
nod = d;
// si refac fluxul atata timp cat nu am ajuns la sursa pe acel path
while (nod != s)
{
int prev = parinte[nod];
edges[edges[prev].pozitie].capacitate += flux;
edges[prev].capacitate -= flux;
nod = edges[prev].sursa;
}
// fluxul maxim calculat
flux_max += flux;
}
}
}
return flux_max;
}
int main () {
ifstream f_cin("cuplaj.in");
ofstream f_cout("cuplaj.out");
f_cin >> n >> m >> e;
nr_noduri = n + m + 2;
// incepem de la 0 consecutiv ca noduri
s = 0;
d = nr_noduri - 1;
adj_indici.resize(nr_noduri);
// preluam muchiile
for (int i = 0; i < e; i++) {
int a, b;
f_cin >> a >> b;
// -->rescalez cumva pe right nodurile
addEdge(a, b + n); // b+n insemnnand ca sunt pe nodurile din right
}
for (int i = 1; i <= n; ++i)
addEdge(s, i);
//muchiile de la sursa la multimea nodurilor left
for (int i = 1; i <= m; ++i)
addEdge(i + n, d);
// aplicam Ford-Fulkerson
f_cout << fluxMaxim() << endl;
// conditia de cuplaj maxim (evit muchiile in nodul start/destinatie artificiale)
// pt afisarea muchiilor saturate din "miez" (left si right)
for (Edge muchie: edges) {
if (muchie.sursa < muchie.destinatie && muchie.sursa != 0 && muchie.destinatie != d && muchie.capacitate == 0)
f_cout << muchie.sursa << " " << muchie.destinatie - n <<endl; // sa nu uit sa rescaluez la val muchiei
}
return 0;
}