二分图
- 二分图
- 什么是二分图
- 染色法判断二分图
- 什么是二分图最大匹配
- 匈牙利算法
- 例题
定义:二分图(特殊图结构),图中的顶点集可以被划分为两个互不相交的子集,且图中边集中每条边的两个端点分别属于两个不同的子集,则称该图为二分图。
二分图中允许偶环存在,不允许奇环存在(偶环就是构成环的边数为偶数条,奇环则边数为奇数)。
仔细想,从一个顶点集的某个顶点出发,走过奇数条边到另一个顶点集,走过偶数条边回到当前顶点。因为每条边的两个端点分别属于两个不用的子集,所以一定符合这种情况。
怎样判定当前图是不是二分图?
染色法:
思路就是dfs或bfs一遍图,用一个全局数组来标记所有点的颜色,1表示第一个集合颜色,里面每个点的颜色都应该为1, 2用来表示另一个集合中点的颜色,相应里面每个点的颜色都应该为2。若x节点颜色为c, 依次遍历x的每一条边,边的另一个端点y:若y此时还没有颜色标记,则用 3 − c 3 - c 3−c去遍历染色y;若y此时有颜色标记,若y的颜色==x的颜色,说明该图不是二分图,因为出现了一条边两个端点属于同一个集合中。
实现代码如下:
#include<iostream>
#include<vector>
using namespace std;
typedef pair<int,int> pii;
const int N = 1e5 + 10;
vector<int> h[N];
vector<int> color(N, 0);
void add(int a, int b) {
h[a].push_back(b);
}
bool dfs(int x, int c) {
color[x] = c;
for(int y : h[x]) {
if(!color[y]) {
if(dfs(y, 3 - c)) return true;
}
else {
if(color[y] == c) return true;
}
}
return false;
}
int main() {
int n, m; cin >> n >> m;
for(int i = 0; i < m; i++) {
int a, b; cin >> a >> b;
add(a, b);
add(b, a);
}
bool flag = false;
for(int i = 1; i <= n; i++) {
if(!color[i]) {
if(dfs(i, 1)) flag = true;
break;
}
}
if(flag) puts("No");
else puts("Yes");
return 0;
}
什么是二分图最大匹配? //推荐视频【D25 二分图最大匹配 匈牙利算法】https://www.bilibili.com/video/BV1GW4y1z7xk?vd_source=4c9eb38d8205116069b961c84f64c958
匈牙利算法:
o(n * m)
在上面链接视频中,董晓算法老师形象将二分图分割的两个顶点集合划分为男女相亲中的男生集合和女生集合,这里建边只用建单向边,通过对男生占,男生让来实现不断动态找增广路,能让则让,就会增加条边的匹配。
例题:P3386 【模板】二分图最大匹配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
实现代码:
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 500 + 10;
int n, m, e, ans;
int vis[N], match[N];
vector<int> h[N];
int dfs(int x) {
for(int y : h[x]) {
if(vis[y]) continue;
vis[y] = 1;
if(!match[y] || dfs(match[y])) {
match[y] = x;
return 1;
}
}
return 0;
}
int main() {
cin >> n >> m >> e;
for(int i = 1; i <= e; i++) {
int u, v; cin >> u >> v;
h[u].push_back(v);
}
for(int i = 1; i <= n; i++) {
memset(vis, 0, sizeof vis);
if(dfs(i)) ans ++;
}
cout << ans;
return 0;
}
C-有大家喜欢的零食吗_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
实现代码:
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 500 + 10;
int n, ans;
vector<int> e[N];
int vis[N], match[N];
int dfs(int x) {
for(int y : e[x]) {
if(vis[y]) continue;
vis[y] = 1;
if(!match[y] || dfs(match[y])) {
match[y] = x;
return 1;
}
}
return 0;
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
int k; cin >> k;
for(int j = 1; j <= k; j++) {
int x; cin >> x;
e[i].push_back(x);
}
}
for(int i = 1; i <= n; i++) {
memset(vis, 0, sizeof vis);
if(dfs(i)) ans++;
}
if(ans == n) cout << "Yes";
else cout << "No\n" << (n - ans);
return 0;
}