二分图
如果一张图能被分为两部分,两部分之间存在边相连,而单个部分内的结点无边相连,那这张图叫做二分图
判断二分图
我们给图进行染色,从一个点开始染成红色,相邻点染蓝色,最后能全部染完,并且任意相邻点颜色不同,说明这是一张二分图。

很好证明:假如从一个点出发,对于一个已经染好色的点,再次访问到时发现需要染另一种颜色,则与开始点形成一个奇数环,这样的话从这个点能染一圈染回来,但是颜色却是矛盾的。
匈牙利算法
之前博哥让我讲过的hh,练练题加深一下
匈牙利算法除了二分图多重匹配之外,在二分图匹配中都能使用,还是比较常用的
大致过程
假如把图分成左右两部分,过程就是令依次遍历左边的结点,去连接右边的结点,如果发现所对应的点已经被之前的点所连,那么让之前的点挪一下(当然,不能挪就别挪了),去连接接下来的点,这是一个递归的过程,递归到能连上为止,如果不行,那说明这个点无法与右边的点匹配。
百度内容:匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法
时间复杂度 O(nm)
代码

#include<bits/stdc++.h>
using namespace std;
int edge[1001][1001], flag[1001], to[1001], n, m, e, ans;
bool find(int x){
for(int j = 1;j <= m;j ++){
if(edge[x][j] && flag[j] == 0){
flag[j] = 1;
if(to[j] == 0 || find(to[j])){
to[j] = x;
return 1;
}
}
}
return 0;
}
int main(){
cin >> n >> m >> e;
for(int i = 1;i <= e;i ++){
int u, v;
cin >> u >> v;
edge[u][v] = 1;
}
for(int i = 1;i <= n;i ++){
memset(flag, 0, sizeof(flag));
if(find(i))
ans++;
}
cout << ans;
return 0;
}
后续找点进阶的题做做。。
有时间浅学一下网络流的板子吧
update:改了改板子,用邻接表的版本
#include<bits/stdc++.h>
using namespace std;
struct node{
int u, v, next;
}edge[110000];
int n, m, e, ans, cnt;
int flag[10001], to[10001], head[10001];
void add(int u, int v){
edge[++cnt].u = u;
edge[cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
inline int find(int x){
for(int i = head[x];i;i = edge[i].next){
int v = edge[i].v;
if(flag[v]) continue;
flag[v] = 1;
if(to[v] == 0 || find(to[v])){
to[v] = x;
return 1;
}
}
return 0;
}
int main(){
cin >> n >> m >> e;
for(int i = 1;i <= e;i ++){
int u , v;
cin >> u >> v;
add(u, v);
}
for(int i = 1;i <= n;i ++){
memset(flag,0,sizeof(flag));
if(find(i))
ans++;
}
cout << ans << endl;
return 0;
}
本文介绍了二分图的概念,即图可以被分为两个互不相交的子集,子集间有边相连但内部无边。讨论了如何判断一个图是否为二分图,通过染色法证明奇数环的存在会导致无法完成染色。接着讲解了匈牙利算法在二分图匹配中的应用,这是一种递归寻找增广路径的方法,用于找到最大匹配。提供的代码示例展示了如何实现匈牙利算法。最后,建议进一步练习相关题目以加深理解,并提及了学习网络流算法的计划。
977

被折叠的 条评论
为什么被折叠?



