#include <iostream>
#include <queue>
#include <vector>
using namespace std;
// find_maximum_matching nájde jedno maximálne párovanie v danom bipartitnom grafe
// "A", "B" sú veľkosti ľavej a pravej partície ("počet chlapcov a dievčat")
// "edge_list" je zoznam dvojíc ("ktoré dvojice sú ochotné spolu tancovať")
// chlapcov aj dievčatá číslujeme od 0
vector< pair<int,int> >
find_maximum_matching(
int A,
int B,
const vector< pair<int,int> > &edge_list)
{
// pre každé dievča si zapamätáme hrany do 'jej' chlapcov
vector< vector<int> > BA;
BA.resize(B);
for (const auto &e : edge_list) BA[ e.second ].push_back( e.first );
// pre každého chlapca si budeme updatovať jeho aktuálnu partnerku
// hodnota -1 znamená, že momentálne žiadnu nemá
vector<int> match(A,-1);
// na začiatku akoby máme všetkých chlapcov a žiadne dievčatá
// postupne po jednom pridávame dievčatá
// z pridaného dievčaťa vždy pustíme BFS ktorým hľadáme zlepšujúcu cestu
for (int b=0; b<B; ++b) {
// pribudlo dievča číslo b, ideme zistiť, či vieme zlepšiť riešenie
// pre každého chlapca si pamätáme, či už bol počas BFS navštívený
// from[a] == -1 : ešte navštívený nebol
// from[a] == a : bol navštívený priamo od dievčaťa b
// from[a] == a2 : bol navštívený tak, že sme od chlapca a2 išli
// k dievčaťu match[a2] a od nej ku chlapcovi a
vector<int> from(A,-1);
// všetkých chlapcov, ktorí sú ochotní tancovať s dievčaťom b,
// zaradíme do fronty na spracovanie a nastavíme im from[]
queue<int> Q;
for (int a : BA[b]) { Q.push(a); from[a]=a; }
// kým sa fronta nevyprázdni, prehľadávame
while (!Q.empty()) {
// vyberieme ďalšieho chlapca na spracovanie
// pozrieme sa, či má v aktuálnom párovaní partnerku
int a = Q.front(); Q.pop();
if (match[a] == -1) {
// tento chlapec nemá partnerku, našli sme teda zlepšujúcu cestu
// upravíme podľa nej párovanie -- "o 1 poposúvame" partnerky
while (from[a] != a) {
// aktuálny chlapec dostane ako partnerku dievča, z ktorého
// sme doň prišli -- teda doterajšiu partnerku chlapca from[a]
match[a] = match[from[a]];
// presunieme sa na toho chlapca a úvahu opakujeme, až kým
// neprejdeme celú cestu
a = from[a];
}
// na konci zlepšujúcej cesty ešte poslednému chlapcovi dáme ako
// novú partnerku práve pribudnuvšie dievča b
match[a] = b;
// a celé prehľadávanie ukončíme
break;
} else {
// práve spracúvaný chlapec partnerku má, pozrieme sa na ňu
// všetkých ostatných chlapcov, ktorí sú s ňou ochotní tancovať
// a ešte neboli objavení prehľadávaním, zaradíme do fronty
// na spracovanie
for (int x : BA[match[a]]) if (from[x]==-1) { Q.push(x); from[x]=a; }
}
}
}
// v tomto okamihu máme zostrojené a v poli match[] zapamätané jedno maximálne
// párovanie, prerobíme ho na zoznam hrán a ten vrátime na výstup
vector< pair<int,int> > result;
for (int a=0; a<A; ++a) if (match[a] != -1) result.push_back( { a, match[a] } );
return result;
}
int main() {
// malý test: 3 chlapci, 3 dievčatá, chlapec 0 tancuje s hociktorou,
// dievča 0 tancuje s hociktorým
// optimálne párovanie je tvorené dvoma dvojicami, napr. 0-2 a 1-0.
vector< pair<int,int> > edge_list = { {0,0}, {0,1}, {0,2}, {1,0}, {2,0} };
cout << find_maximum_matching(3, 3, edge_list).size() << endl;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8cXVldWU+CiNpbmNsdWRlIDx2ZWN0b3I+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgovLyBmaW5kX21heGltdW1fbWF0Y2hpbmcgbsOhamRlIGplZG5vIG1heGltw6FsbmUgcMOhcm92YW5pZSB2IGRhbm9tIGJpcGFydGl0bm9tIGdyYWZlCi8vICJBIiwgIkIiIHPDuiB2ZcS+a29zdGkgxL5hdmVqIGEgcHJhdmVqIHBhcnTDrWNpZSAoInBvxI1ldCBjaGxhcGNvdiBhIGRpZXbEjWF0IikKLy8gImVkZ2VfbGlzdCIgamUgem96bmFtIGR2b2rDrWMgKCJrdG9yw6kgZHZvamljZSBzw7ogb2Nob3Ruw6kgc3BvbHUgdGFuY292YcWlIikKLy8gY2hsYXBjb3YgYWogZGlldsSNYXTDoSDEjcOtc2x1amVtZSBvZCAwCgp2ZWN0b3I8IHBhaXI8aW50LGludD4gPgpmaW5kX21heGltdW1fbWF0Y2hpbmcoCiAgICAgICAgaW50IEEsCiAgICAgICAgaW50IEIsCiAgICAgICAgY29uc3QgdmVjdG9yPCBwYWlyPGludCxpbnQ+ID4gJmVkZ2VfbGlzdCkKewoKICAgIC8vIHByZSBrYcW+ZMOpIGRpZXbEjWEgc2kgemFwYW3DpHTDoW1lIGhyYW55IGRvICdqZWonIGNobGFwY292CgogICAgdmVjdG9yPCB2ZWN0b3I8aW50PiA+IEJBOwogICAgQkEucmVzaXplKEIpOwogICAgZm9yIChjb25zdCBhdXRvICZlIDogZWRnZV9saXN0KSBCQVsgZS5zZWNvbmQgXS5wdXNoX2JhY2soIGUuZmlyc3QgKTsKCiAgICAvLyBwcmUga2HFvmTDqWhvIGNobGFwY2Egc2kgYnVkZW1lIHVwZGF0b3ZhxaUgamVobyBha3R1w6FsbnUgcGFydG5lcmt1CiAgICAvLyBob2Rub3RhIC0xIHpuYW1lbsOhLCDFvmUgbW9tZW50w6FsbmUgxb5pYWRudSBuZW3DoQogICAgCiAgICB2ZWN0b3I8aW50PiBtYXRjaChBLC0xKTsKCiAgICAvLyBuYSB6YcSNaWF0a3UgYWtvYnkgbcOhbWUgdsWhZXRrw71jaCBjaGxhcGNvdiBhIMW+aWFkbmUgZGlldsSNYXTDoQogICAgLy8gcG9zdHVwbmUgcG8gamVkbm9tIHByaWTDoXZhbWUgZGlldsSNYXTDoQogICAgLy8geiBwcmlkYW7DqWhvIGRpZXbEjWHFpWEgdsW+ZHkgcHVzdMOtbWUgQkZTIGt0b3LDvW0gaMS+YWTDoW1lIHpsZXDFoXVqw7pjdSBjZXN0dQoKICAgIGZvciAoaW50IGI9MDsgYjxCOyArK2IpIHsKCiAgICAgICAgLy8gcHJpYnVkbG8gZGlldsSNYSDEjcOtc2xvIGIsIGlkZW1lIHppc3RpxaUsIMSNaSB2aWVtZSB6bGVwxaFpxaUgcmllxaFlbmllCgogICAgICAgIC8vIHByZSBrYcW+ZMOpaG8gY2hsYXBjYSBzaSBwYW3DpHTDoW1lLCDEjWkgdcW+IGJvbCBwb8SNYXMgQkZTIG5hdsWhdMOtdmVuw70KICAgICAgICAvLyBmcm9tW2FdID09IC0xIDogZcWhdGUgbmF2xaF0w612ZW7DvSBuZWJvbAogICAgICAgIC8vIGZyb21bYV0gPT0gYSAgOiBib2wgbmF2xaF0w612ZW7DvSBwcmlhbW8gb2QgZGlldsSNYcWlYSBiCiAgICAgICAgLy8gZnJvbVthXSA9PSBhMiA6IGJvbCBuYXbFoXTDrXZlbsO9IHRhaywgxb5lIHNtZSBvZCBjaGxhcGNhIGEyIGnFoWxpCiAgICAgICAgLy8gICAgICAgICAgICAgICAgIGsgZGlldsSNYcWldSBtYXRjaFthMl3CoGEgb2QgbmVqIGt1IGNobGFwY292aSBhCgogICAgICAgIHZlY3RvcjxpbnQ+IGZyb20oQSwtMSk7CgogICAgICAgIC8vIHbFoWV0a8O9Y2ggY2hsYXBjb3YsIGt0b3LDrSBzw7ogb2Nob3Ruw60gdGFuY292YcWlIHMgZGlldsSNYcWlb20gYiwKICAgICAgICAvLyB6YXJhZMOtbWUgZG8gZnJvbnR5IG5hIHNwcmFjb3ZhbmllIGEgbmFzdGF2w61tZSBpbSBmcm9tW10KCiAgICAgICAgcXVldWU8aW50PiBROwogICAgICAgIGZvciAoaW50IGEgOiBCQVtiXSkgeyBRLnB1c2goYSk7IGZyb21bYV09YTsgfQoKICAgICAgICAvLyBrw71tIHNhIGZyb250YSBuZXZ5cHLDoXpkbmksIHByZWjEvmFkw6F2YW1lCgogICAgICAgIHdoaWxlICghUS5lbXB0eSgpKSB7CgogICAgICAgICAgICAvLyB2eWJlcmllbWUgxI9hbMWhaWVobyBjaGxhcGNhIG5hIHNwcmFjb3ZhbmllCiAgICAgICAgICAgIC8vIHBvenJpZW1lIHNhLCDEjWkgbcOhIHYgYWt0dcOhbG5vbSBww6Fyb3ZhbsOtIHBhcnRuZXJrdQogICAgICAgICAgICAKICAgICAgICAgICAgaW50IGEgPSBRLmZyb250KCk7IFEucG9wKCk7CgogICAgICAgICAgICBpZiAobWF0Y2hbYV0gPT0gLTEpIHsKCiAgICAgICAgICAgICAgICAvLyB0ZW50byBjaGxhcGVjIG5lbcOhIHBhcnRuZXJrdSwgbmHFoWxpIHNtZSB0ZWRhIHpsZXDFoXVqw7pjdSBjZXN0dQogICAgICAgICAgICAgICAgLy8gdXByYXbDrW1lIHBvZMS+YSBuZWogcMOhcm92YW5pZSAtLSAibyAxIHBvcG9zw7p2YW1lIiBwYXJ0bmVya3kKCiAgICAgICAgICAgICAgICB3aGlsZSAoZnJvbVthXSAhPSBhKSB7IAoKICAgICAgICAgICAgICAgICAgICAvLyBha3R1w6FsbnkgY2hsYXBlYyBkb3N0YW5lIGFrbyBwYXJ0bmVya3UgZGlldsSNYSwgeiBrdG9yw6lobwogICAgICAgICAgICAgICAgICAgIC8vIHNtZSBkb8WIIHByacWhbGkgLS0gdGVkYSBkb3RlcmFqxaFpdSBwYXJ0bmVya3UgY2hsYXBjYSBmcm9tW2FdCgogICAgICAgICAgICAgICAgICAgIG1hdGNoW2FdID0gbWF0Y2hbZnJvbVthXV07IAoKICAgICAgICAgICAgICAgICAgICAvLyBwcmVzdW5pZW1lIHNhIG5hIHRvaG8gY2hsYXBjYSBhIMO6dmFodSBvcGFrdWplbWUsIGHFviBrw71tCiAgICAgICAgICAgICAgICAgICAgLy8gbmVwcmVqZGVtZSBjZWzDuiBjZXN0dQoKICAgICAgICAgICAgICAgICAgICBhID0gZnJvbVthXTsgCiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgLy8gbmEga29uY2kgemxlcMWhdWrDumNlaiBjZXN0eSBlxaF0ZSBwb3NsZWRuw6ltdSBjaGxhcGNvdmkgZMOhbWUgYWtvCiAgICAgICAgICAgICAgICAvLyBub3bDuiBwYXJ0bmVya3UgcHLDoXZlIHByaWJ1ZG51dsWhaWUgZGlldsSNYSBiCgogICAgICAgICAgICAgICAgbWF0Y2hbYV0gPSBiOwoKICAgICAgICAgICAgICAgIC8vIGEgY2Vsw6kgcHJlaMS+YWTDoXZhbmllIHVrb27EjcOtbWUKCiAgICAgICAgICAgICAgICBicmVhazsKCiAgICAgICAgICAgIH0gZWxzZSB7CgogICAgICAgICAgICAgICAgLy8gcHLDoXZlIHNwcmFjw7p2YW7DvSBjaGxhcGVjIHBhcnRuZXJrdSBtw6EsIHBvenJpZW1lIHNhIG5hIMWIdQogICAgICAgICAgICAgICAgLy8gdsWhZXRrw71jaCBvc3RhdG7DvWNoIGNobGFwY292LCBrdG9yw60gc8O6IHMgxYhvdSBvY2hvdG7DrSB0YW5jb3ZhxaUKICAgICAgICAgICAgICAgIC8vICAgICBhIGXFoXRlIG5lYm9saSBvYmphdmVuw60gcHJlaMS+YWTDoXZhbsOtbSwgemFyYWTDrW1lIGRvIGZyb250eQogICAgICAgICAgICAgICAgLy8gICAgIG5hIHNwcmFjb3ZhbmllCgogICAgICAgICAgICAgICAgZm9yIChpbnQgeCA6IEJBW21hdGNoW2FdXSkgaWYgKGZyb21beF09PS0xKSB7IFEucHVzaCh4KTsgZnJvbVt4XT1hOyB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgLy8gdiB0b210byBva2FtaWh1IG3DoW1lIHpvc3Ryb2plbsOpIGEgdiBwb2xpIG1hdGNoW10gemFwYW3DpHRhbsOpIGplZG5vIG1heGltw6FsbmUKICAgIC8vIHDDoXJvdmFuaWUsIHByZXJvYsOtbWUgaG8gbmEgem96bmFtIGhyw6FuIGEgdGVuIHZyw6F0aW1lIG5hIHbDvXN0dXAKCiAgICB2ZWN0b3I8IHBhaXI8aW50LGludD4gPiByZXN1bHQ7CiAgICBmb3IgKGludCBhPTA7IGE8QTsgKythKSBpZiAobWF0Y2hbYV0gIT0gLTEpIHJlc3VsdC5wdXNoX2JhY2soIHsgYSwgbWF0Y2hbYV0gfSApOwogICAgcmV0dXJuIHJlc3VsdDsKfQoKaW50IG1haW4oKSB7CiAgICAvLyBtYWzDvSB0ZXN0OiAzIGNobGFwY2ksIDMgZGlldsSNYXTDoSwgY2hsYXBlYyAwIHRhbmN1amUgcyBob2Npa3Rvcm91LCAKICAgIC8vIGRpZXbEjWEgMCB0YW5jdWplIHMgaG9jaWt0b3LDvW0KICAgIC8vIG9wdGltw6FsbmUgcMOhcm92YW5pZSBqZSB0dm9yZW7DqSBkdm9tYSBkdm9qaWNhbWksIG5hcHIuIDAtMiBhIDEtMC4KCiAgICB2ZWN0b3I8IHBhaXI8aW50LGludD4gPiBlZGdlX2xpc3QgPSB7IHswLDB9LCB7MCwxfSwgezAsMn0sIHsxLDB9LCB7MiwwfSB9OwogICAgY291dCA8PCBmaW5kX21heGltdW1fbWF0Y2hpbmcoMywgMywgZWRnZV9saXN0KS5zaXplKCkgPDwgZW5kbDsKfQ==