您的位置:首页 > 其它

二分图最大匹配-匈牙利算法

2016-10-20 17:04 246 查看
二分图的定义:如果一个图的所有顶点可以被分为X和Y两个集合,并且所有边的两个顶点恰好一个属于集合X,另一个属于集合Y,即每个集合内的顶点没有边相连,那么此图就是二分图。



增广路:增广路的本质就是一条路径的起点和终点都是未被配对的点。

如果找到一条增广路,那么配对数将会加1.

寻找一个点配对的基本思路:

1.从点u开始,从点u引出的边中任意选一条边(u-v)开始配对。如果此时v还没有被配对,则配对成功,找到一条增广路。如果点v已被配对,就尝试进行“连锁反应”,如果尝试成功,则找到一条增广路,并更新配对关系。

2.如果刚才所选的边配对失败,就重新选一条边尝试。直到点u配对成功,或者尝试过点u所有的边为止。

#include<iostream>
#include<cstdio>
using namespace std;

int node[50],next[50],root[50],cnt,m,n;
int match[50],book[50];
//match[x]用来存储x配对的对象,book[x]标记x是否已被访问
int sum;

//二分图都是无向图
void insert(int u, int v) {
cnt++;
node[cnt] = v;
next[cnt] = root[u];
root[u] = cnt;
}
void build() {
for (int i=1; i<=m; i++) {
int u,v;
cin >> u >> v;
insert(u,v);
insert(v,u);
}
}

//寻找一个点的匹配
bool dfs(int u)
{
for (int x=root[u]; x!=-1; x=next[x])
if (!book[node[x]]) {
book[node[x]] = 1;
if (match[node[x]] == -1 || dfs(match[node[x]])) { //一旦发现寻找增广路可行(dfs的值为1),就向前返回修改match数组的值
match[node[x]] = u;
match[u] = node[x];
return 1; //找到增广路,返回 1
}
}
return 0; //连锁反应失败,返回 0
}

int main()
{
cin >> n >> m;
for (int i=1; i<=m; i++) next[i] = -1;
for (int i=1; i<=n; i++) root[i] = -1;
build();

for (int i=1; i<=n; i++) match[i] = -1;

for (int i=1; i<=n; i++) {
for (int j=1; j<=n; j++) book[j] = 0; //清空上次搜索时的访问标记,只留下match的配对标记。因为如一个点已经选过,可以引发连锁反应。
if (dfs(i)) sum++; //此时sum存储的是前i个点的最大匹配
//因为是最大匹配,所以只要找到一条增广路,sum就加1,后面的搜索是寻找有无新的增广路。
}
cout << sum;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: