讲解:
别人的博客传送门,图做的真的很棒:传送门
模板:
成员:
const int maxn = 207;
int n,m;//n个点,m条边
bool col[maxn];//对点进行染色
bool vis[maxn];//标记点
int link[maxn];//将两点进行连接
vector<int> edge[maxn];//邻接表
void addedge (int u, int v) {//加边,根据题意双向还是单向
edge[u].push_back(v);
edge[v].push_back(u);
}
染色判断是否是二分图:
bool color (int u) {//染色判断是否是二分图,如果不是返回false
for (auto v : edge[u]) {
if (!col[v]) {//如果这个点没有被染过色
col[v] = !col[u];//将这个点染成和他父节点相反的颜色
if (!color(v)) return false;//然后再从这个点出发继续染色,如果染色失败返回false
} else if (col[v] == col[u]) return false;
//如果这个点已经染色而且和它的父节点一样,说明不是二分图,返回false
}
return true;
}
在这张图是二分图的前提下进行DFS增广:
bool dfs(int u) {
//进行dfs增广,一旦找到一个未匹配的点或者是可以进行增广的点就返回true
for(auto v = edge[u].begin() ; v!=edge[u].end() ; v++) {
if(!vis[*v]) {
vis[*v] = true;//这里不要忘了将点标为已访问避免死循环
if(link[*v] == -1 || dfs(link[*v])) {
//如果这个点没有被配对,说明这是一条增广路
//或者是从这个点所在边的另一点可以找到增广路
link[*v] = u;
link[u] = *v;
//将两点进行连接
return true;
}
}
}
return false;//这里不要忘了写
}
匈牙利算法主体:
int match() {
int ans{};
clr(link, -1);//将所有的点置为未连接
for (int i = 1; i <= n; i++)
if (link[i] == -1) {//如果这个点没有和其它点连边
clr(vis, 0);//初始化
if (dfs(i)) ans++;//如果找到增广路说明最大匹配+1
}
return ans;
}
全家福:
const int maxn = 207;
int n,m;//n个点,m条边
bool col[maxn];//对点进行染色
bool vis[maxn];//标记点
int link[maxn];//将两点进行连接
vector<int> edge[maxn];
void addedge (int u, int v) {//加边,根据题意双向还是单向
edge[u].push_back(v);
edge[v].push_back(u);
}
bool color (int u) {//染色判断是否是二分图,如果不是返回false
for (auto v : edge[u]) {
if (!col[v]) {//如果这个点没有被染过色
col[v] = !col[u];//将这个点染成和他父节点相反的颜色
if (!color(v)) return false;//然后再从这个点出发继续染色,如果染色失败返回false
} else if (col[v] == col[u]) return false;
//如果这个点已经染色而且和它的父节点一样,说明不是二分图,返回false
}
return true;
}
bool dfs(int u) {
//进行dfs增广,一旦找到一个未匹配的点或者是可以进行增广的点就返回true
for(auto v = edge[u].begin() ; v!=edge[u].end() ; v++) {
if(!vis[*v]) {
vis[*v] = true;//这里不要忘了将点标为已访问避免死循环
if(link[*v] == -1 || dfs(link[*v])) {
//如果这个点没有被配对,说明这是一条增广路
//或者是从这个点所在边的另一点可以找到增广路
link[*v] = u;
link[u] = *v;
//将两点进行连接
return true;
}
}
}
return false;//这里不要忘了写
}
int match() {
int ans{};
clr(link, -1);//将所有的点置为未连接
for (int i = 1; i <= n; i++)
if (link[i] == -1) {//如果这个点没有和其它点连边
clr(vis, 0);//初始化
if (dfs(i)) ans++;//如果找到增广路说明最大匹配+1
}
return ans;
}
void init () {
clr(col,0);
//不要忘了对vector的初始化
for(int i=1 ; i<=n ; i++) edge[i].clear();
}
例题:
注意:
这里需要留意一下匈牙利树的概念,在开头贴的讲解里有提到,不然KM算法学起来会稍微有些吃力。