Pagini recente » Cod sursa (job #2026759) | Cod sursa (job #2961879)
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
ifstream fin("cuplaj.in");
ofstream fout("cuplaj.out");
//Problema cuplajului iin graf bipartit se rezolva cu ajutorul algoritmului de determinare
//al fluxului intr-o retea de transport
//ca sa facem asta, adaugam un nod de start 0 si unul de destinatie n+m+1, si nodul de start il conectam
//la toate nodurile din prima grupa cu capacitate 0, iar nodurile din a doua grupa le conectam la destinatie cu capacitate 1
//de asemenea, punem capacitate 1 intre toate nodurile ce duc din grupa 1 in grupa 2
//calculam flux maxim pe reteaua creata si apoi muchiile ce duc din prima grupa in a doua care au fluxul maxim(1), sunt
//muchiile care fac parte din cuplajul maxim
//fluxul maxim e cuplajul maxim
int n, m, e, N;
int viz[20001];
pair<int, int>tata[20001];//ca sa retin nodurile vizitate si tatal nodurilor pentru reconstruirea drumului
//pentru tata retinem nodul si pozitia unde s-ar afla tatal in lista nodului curent
vector<vector<pair<pair<int, int>, int>>> lista(20001);//lista de muchii (vecin, capacitate, pozitia din lista vecinului care ar indica spre nodul respectiv)
int bfs(){//bfs pentru aflarea existentei drumului de crestere
queue<int> coada;
coada.push(0);
for(int i = 0; i <= N; i++){
tata[i] = {-1, -1};
viz[i] = 0;
}
viz[0]++;
while(coada.size()!=0){
int nod_cur = coada.front();
if(nod_cur == N)//daca am ajuns la final inseamna ca am gasit un drum de crestere
return 1;
int cnt = 0;//ca sa retinem pt fiecare vecin pozitia pe care o aveau in lista nodului
for(int i = 0; i < lista[nod_cur].size(); i++){
int nod_vec = lista[nod_cur][i].first.first;
if(lista[nod_cur][i].first.second > 0 && viz[nod_vec] == 0){//daca am gasit un nod prin care nu am mai fost care mai are loc, trecem prin el
viz[nod_vec]++;
tata[nod_vec] = {nod_cur, cnt};//retinem tatal si pozitia
coada.push(nod_vec);
}
cnt++;
}
coada.pop();//scot din coada nodul prin care deja am trecut
}
return 0;//nu am gasit
}
int Edmonds_Karp(){
int max_flux = 0;//fluxul maixim
while(bfs()){//cat timp avem drum de crestere
for(int i = 0; i < lista[N].size(); i++){
int nod_cur = lista[N][i].first.first;
if(lista[nod_cur][lista[N][i].second].first.second > 0 && viz[nod_cur]){//daca este drum care a dus de la vecinul lui n la n care mai are capacitate
//si a fost vizitat in verificarea noastra, atunci reconstituim drumul parcurs
int minim = 9999999;//bottleneckul nostru
tata[N] = {nod_cur, lista[N][i].second};
int drum = N;
while(tata[drum].first!=-1){//traversam invers drumul de crestere de la destinatie la start ca sa gasim bottleneck ul
minim = min(minim, lista[tata[drum].first][tata[drum].second].first.second);
drum = tata[drum].first;
}
max_flux += minim;//il adaugam la flux doarece e cea mai mare valoare pe care o putem trece prin acel drum
drum = N;
while(tata[drum].first!=-1){//reluam drumul de crestere ca sa actualizam capacitatile nodurilor
lista[tata[drum].first][tata[drum].second].first.second -= minim;
lista[drum][lista[tata[drum].first][tata[drum].second].second].first.second += minim;
drum = tata[drum].first;
}
}
}
}
return max_flux;//fluxul maxim
}
int main()
{
fin>>n>>m>>e;
N = n + m + 1;
//creem lista de adiacenta de care am vorbit
for(int i = 0; i < e; i++){
int u, v;
fin>>u>>v;
lista[u].push_back({{v+n ,1}, lista[v+n].size()});
lista[v+n].push_back({{u, 0}, lista[u].size()-1});
}
for(int i = 1; i <= n; i++){
lista[0].push_back({{i, 1}, lista[i].size()});
lista[i].push_back({{0, 0}, lista[0].size()-1});
}
for(int i = 1; i <= m; i++){
lista[i+n].push_back({{n+m+1, 1}, lista[N].size()});
lista[n+m+1].push_back({{i+n, 0}, lista[i+n].size()-1});
}
fout<<Edmonds_Karp()<<"\n";//cuplaj maxim
for(int i = 1; i <= n; i++)//gasim nodurile care au capacitatea ocupata care duc din prima grupa in a doua
for(int j = 0; j <lista[i].size(); j++){
if(lista[i][j].first.second != 1 && lista[i][j].first.first != 0)
fout<<i<<" "<<lista[i][j].first.first - n<<"\n";
}
}