Bipartite Graph
二分图 中的点由两个集合组成,且两个集合内部没有边。二分图不存在长度为奇数的环。
Check whether a given graph is Bipartite or not (Backtracking algorithm m coloring problem)
如果两个集合中的点分别染成黑色和白色,二分图中的每一条边都一定是连接一个黑色点和一个白色点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| vector<int> E[N]; int color[N]; bool bipartite(int u) { for (auto v : E[u]) { if (color[v] == color[u]) return 0; if (color[v] == 0) { color[v] = -color[u]; if (!bipartite(v)) return 0; } } return 1; } void eachT() { for { E[u].push_back(v); E[v].push_back(u); } color[1] = 1; printf("%s\n", bipartite(1) ? "Yes" : "No"); }
|
Hungarian Algorithm for Bipartite Graph
匹配 (matching):任意两条边都没有公共顶点边的集合。
使用 Hungarian 定理求二分图的 最大匹配数(所含匹配边数最多的匹配) 和 最小点覆盖数(最少的点的数量使二分图所有的边都至少有一个端点在这些点之中),根据 König 定理,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| vector<int> E[N]; int npy[N], vis[N];
bool found(int u) { for (auto v : E[u]) { if (vis[v]) continue; vis[v] = 1; if (npy[v] == -1 || found(npy[v])) { npy[v] = u; return 1; } } return 0; }
void eachT() { for { E[u].push_back(v); } int cnt = 0; for (int j = 1; j <= n; ++j) npy[j] = -1; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) vis[j] = 0; cnt += found(i); } printf("%d\n", cnt); }
|
应用:
- 黑白棋盘,可选择交换两行或交换两列,能否在若干次操作后,使棋盘的主对角线均为黑色。
- 黑白棋盘,可选择将某一行或某一列的白色全部变为黑色,求将棋盘全变为黑色的最小操作次数。