Pagini recente » Cod sursa (job #1328928) | Cod sursa (job #2700997) | Cod sursa (job #2594627) | Cod sursa (job #2184384) | Cod sursa (job #2965859)
#include <bits/stdc++.h>
using namespace std;
ifstream fin("cuplaj.in");
ofstream fout("cuplaj.out");
int N, n, m, k, x, y, maxflow;
vector<pair<int, int>> g[100005];
queue<int> q;
bool viz[20007];
int parent[20007];
void read()
{
fin >> n >> m >> k;
/// S=0, multimea A = {1,2...,n}, multimea B = {n+1,...,n+m}, T=n+m+1
N = n + m + 1;
for(int i = 0; i < k; ++i)
{
fin >> x >> y;
g[x].emplace_back(y+n,1);
g[y+n].emplace_back(x, 0);
}
/// adaugam muchii de la sursa la fiecare nod din multimea A
for(int i = 1; i <= n; ++i) {
g[0].emplace_back(i, 1);
g[i].emplace_back(0, 0);
}
/// adaugam muchii de la fiecare nod din multimea B la sink
for(int i = n + 1; i <= n + m; ++i) {
g[i].emplace_back(n + m + 1, 1);
g[n + m + 1].emplace_back(i, 0);
}
}
void afis(){
for(int i = 1; i < N; ++i){
for(auto nod : g[i]){
if(!nod.second && nod.first > n && nod.first != N)
fout << i <<" " << nod.first - n << '\n';
}
}
}
int bfs()
{
/// folosim bfs pentru a verifica daca mai este un drum de la s la t
/// folosim vectorul parent pentru a putea reconstrui drumul
/// reinitializam tot
while (!q.empty())
q.pop();
for (int i = 0; i <= N; i++)
{
parent[i] = 0;
viz[i] = false;
}
q.push(0);
viz[0] = true;
/// bfs
while (!q.empty())
{
auto nod = q.front();
q.pop();
/// n reprezinta destinatia deci returnam true deoarece am gasit drum
if (nod == N) return true;
for (auto p : g[nod])
if (!viz[p.first] && p.second > 0)
{
q.push(p.first);
parent[p.first] = nod;
viz[p.first] = true;
}
}
return false;
}
inline int flux()
{
/// cat timp avem drumuri
while (bfs())
{
for (int i = 0; i <= N; i++)
{
for(auto p : g[i]){
if(p.first == N && p.second > 0 && viz[i])
{
int leaf = i;
/// construim drumul
vector<int> path;
path.emplace_back(N);
path.emplace_back(leaf);
int nod = parent[leaf];
if (nod == 0)
path.emplace_back(nod);
else {
while (nod != 0) {
path.emplace_back(nod);
nod = parent[nod];
}
path.emplace_back(0);
}
/// dupa ce am gasit drumul, vedem care este flow-ul minim si adaugam la rezultatul final
int flow_minim = INT_MAX;
for (auto it = path.rbegin(); it != path.rend(); ++it) {
int current_flow;
for(auto p : g[*it])
if(p.first == *(it+1))
current_flow = p.second;
flow_minim = min(flow_minim, current_flow);
}
maxflow += flow_minim;
// Iterate through path in reverse order
for (auto it = path.rbegin(); it != path.rend() - 1; ++it) {
// Iterate through edges of g[path[j]]
for (auto &edge : g[*it]) {
if (edge.first == *(it+1))
edge.second -= flow_minim;
}
// Iterate through edges of g[path[j+1]]
for (auto &edge : g[*(it+1)]) {
if (edge.first == *it)
edge.second += flow_minim;
}
}
/// pt reconstruirea flow-ului
// /// scadem flow_minim din muchiile inspre destinatie si adunam pe muchiile in directie opusa
// for (int j = 0; j < path.size() - 1; j++) {
// for (int it = 0; it < g[path[j]].size(); ++it)
// if(g[path[j]][it].first == path[j + 1])
// g[path[j]][it].second -= flow_minim;
/// pt graful rezidual
// for(int it = 0; it < g[path[j+1]].size(); ++it)
// if(g[path[j+1]][it].first == path[j])
// g[path[j+1]][it].second += flow_minim;
}
}
}
}
}
return maxflow;
}
int main()
{
read();
fout << flux() << "\n";
afis();
return 0;
}