#include <bits/stdc++.h> // NeOWami
using namespace std;
#define ft first
#define sc second
const int N = 2e5 + 5;
int n, m, k;
int L[N], R[N], vis[N], vers = 0;
vector<int> D[N], G[N];
bool dfs(int u) {
vis[u] = vers;
for (int v: D[u]) if (!L[v]) {
L[v] = u;
R[u] = v;
return 1;
}
for (int v: D[u]) if (vis[L[v]] != vers && dfs(L[v])) {
L[v] = u;
R[u] = v;
return 1;
}
return 0;
}
void maximumMatching() {
while(1) {
vers++;
bool ok = 0;
for (int u = 1; u <= n; u++) if (!R[u] && dfs(u)) ok = 1;
if (!ok) break;
}
}
void cover(int u) {
vis[u] = 1;
for (int v: G[u]) if (!vis[v]) cover(v);
}
void minimumVertexCover() {
fill(vis + 1, vis + n + m + 1, 0);
for (int u = 1; u <= n; u++) {
for (int v: D[u]) {
if (v != R[u]) G[u].push_back(v);
else G[v].push_back(u);
}
}
for (int u = 1; u <= n; u++) if (!R[u] && !vis[u]) cover(u);
}
signed main() {
cin.tie(NULL)->sync_with_stdio(false);
if(ifstream("FOODS.inp")) {
freopen("FOODS.inp", "r", stdin);
freopen("FOODS.out", "w", stdout);
}
cin >> n >> m >> k;
for (int i = 1; i <= k; i++) {
int u, v; cin >> u >> v;
v += n;
D[u].push_back(v);
}
maximumMatching();
minimumVertexCover();
vector<int> P, Q;
for (int u = 1; u <= n; u++) if (!(R[u] && !vis[u])) P.push_back(u);
for (int v = n + 1; v <= n + m; v++) if (!(L[v] && vis[v])) Q.push_back(v - n);
cout << P.size() << " " << Q.size() << '\n';
for (int item: P) cout << item << " ";
for (int item: Q) cout << item << " ";
return 0;
}
/*
cho đồ thị 2 phía n (trái), m (phải), k(cạnh)
cần tìm max n0 + m0 đỉnh sao cho không có đỉnh nào trong tập n0 có cạnh nối tới đỉnh bất kì trong m0:
Có thể đây chính là bài Maximum independent set in Bipartite graph
Maximum independent set in Bipartite graph = |Node| - Maximum Matching
(chx chứng minh được):
Và trace sẽ là những đỉnh còn lại chưa được đánh dấu trong bài Minimum vertex cover in bipartite graph
Nhắc lại bài Minimum vertex cover in bipartie graph:
*Minimum vertex cover in bipartite graph.
->Để tìm số đỉnh tối thiểu để bao phủ hết các cạnh trong đồ thị 2 phía, ta chỉ cần tìm cặp ghép cực đại
Vì:
+ Kőnig's theorem (graph theory) cho rằng: trong đồ thị vô hướng số lượng đỉnh trong tập hợp
độc lập lớn nhất >= cặp ghép cực đại. Từ đó suy ra Cặp ghép cực đại = số đỉnh cực tiểu bao phủ
# Chứng minh: https://c...content-available-to-author-only...s.com/blog/entry/105697
# Video: https://w...content-available-to-author-only...e.com/watch?v=K-g5AzHACWs
+ Để trace, tìm lại các đỉnh đó, ta làm như sau
- Giả sử đã tìm được M cạnh của cặp ghép cực đại.
- Hãy định nghĩa hướng của các cạnh. Những cạnh thuộc tập M sẽ đi từ phải sang trái, còn lại đi từ trái sang phải
- Bây giờ, hãy Dfs từ TẤT CẢ các đỉnh BÊN TRÁI KHÔNG thuộc tập M
- Một số đỉnh của đồ thị sẽ được đánh dấu là đã thăm trong quá trình DFS này và một số không được thăm.
- Để có được bộ che đỉnh tối thiểu, bạn lấy tất cả các đỉnh bên phải ĐÃ được thăm của M, và tất cả các đỉnh bên trái CHƯA được thăm của M.
# Chứng minh bằng phản chứng:
Lấy một cạnh (l, r) mà giả sử không được bao phủ
và xem xét cả bốn trường hợp liên quan đến l và r có liên quan đến các cạnh trong M hay không.
Trong tất cả những trường hợp này sẽ có một mâu thuẫn với cách mà chúng ta đã thực hiện DFS
và thực tế rằng M là một sự khớp tối đa.
# Nguồn: https://c...content-available-to-author-only...s.com/blog/entry/17534
Ví dụ: Bài LIGHTING (CHIẾU SÁNG)
*/