二分图匹配之 匈牙利算法简单学习后感
2017-02-18 18:33
316 查看
匈牙利算法的核心就是 增广路定理,能够理解增广路定理其实就理论理解了 匈牙利算法。
讲匈牙利算法的文章很多了,就不在这里关公面前耍大刀了。
个人对匈牙利算法的理解:
先将图分为左边的点,和右边的点以后。
对左边的每一个没有匹配的点,进行搜索是否有增广路,如果搜寻到了, 就可以 使当前这个左边的点成为匹配点的同时,使匹配边数+1
可能我这么说也没有说清楚,网上有大牛的更好的讲解的文章,帮助会更大一些。我想说的是 匈牙利算法由于题目出现的两个情况,而出现的两个写法。
一种就是简单版本。
题目例子是:
HDU 1068 男孩和女孩:http://acm.hdu.edu.cn/showproblem.php?pid=1068
这种题目的特点就是: 构成二分图的 左边点和右边点,是混在一起编号,然后给你的。
这样一来,左边的点和右边的点不用分清。 对所有点进行 增广路搜索(DFS)就好了。
代码里的两个数组:
book 是 每一次增光路搜索,判断点有没有搜过。
ans 是 在整个过程中, 记录了每个点的匹配点是什么。
PS: 二分图匹配过程中,每个点要么没有匹配点,要么有且只有一个匹配点
这是我的在这种情况的代码,不是本题的代码....
还有一种情况应该更大众吧,就是
左边的点和右边的点 分开编号给出,都从0或者1 开始编号。
这样子就不能一股脑的搜索了。有可能做题的人没有意识到,但是用上面的办法去做应该会很乱很扯....
而且我看到了 kuangbin大神的代码,一直没看懂。 后来自己想通了,很幸运发现和kuangbin大神的想法是一样的.....
题目例子是:
POJ 1469:http://poj.org/problem?id=1469 课程匹配问题。
因为题目已经分好了左边的点和右边的点。
所以对每个左边的点进行搜索。
去掉了判断这个点是不是没有匹配点。
因为,每个点起初都是没有匹配的。而当前点,是不可能被前面的点 给变成匹配点的。
这个判断也就显得多余。
这里面的两个数组:
book 表示
在每一次搜索中,右边的点有没有被 搜索过。
ans 表示
在整个过程中 ,
右边的点 对应的 匹配点!!
这个情况下的代码:(饿,是此题的代码)
讲匈牙利算法的文章很多了,就不在这里关公面前耍大刀了。
个人对匈牙利算法的理解:
先将图分为左边的点,和右边的点以后。
对左边的每一个没有匹配的点,进行搜索是否有增广路,如果搜寻到了, 就可以 使当前这个左边的点成为匹配点的同时,使匹配边数+1
可能我这么说也没有说清楚,网上有大牛的更好的讲解的文章,帮助会更大一些。我想说的是 匈牙利算法由于题目出现的两个情况,而出现的两个写法。
一种就是简单版本。
题目例子是:
HDU 1068 男孩和女孩:http://acm.hdu.edu.cn/showproblem.php?pid=1068
这种题目的特点就是: 构成二分图的 左边点和右边点,是混在一起编号,然后给你的。
这样一来,左边的点和右边的点不用分清。 对所有点进行 增广路搜索(DFS)就好了。
代码里的两个数组:
book 是 每一次增光路搜索,判断点有没有搜过。
ans 是 在整个过程中, 记录了每个点的匹配点是什么。
PS: 二分图匹配过程中,每个点要么没有匹配点,要么有且只有一个匹配点
这是我的在这种情况的代码,不是本题的代码....
#include"cstdio" #include"cstring" #include"vector" using namespace std; #define inf 99999 int n,m; //点,边 int res; //匹配数 int ans[inf]; //各点对应妻子,or -1 int book[inf]; //交替路标记 vector<int>edge[inf]; int dfs(int u) { int len=edge[u].size(); for(int i=0;i<len;i++) { int v=edge[u][i]; if(!book[v]) { book[v]=1; if(ans[v]==-1||dfs(ans[v])) { ans[v]=u; ans[u]=v; return 1; } } } return 0; } int XYL() { int i,j; for(i=0;i<n;i++) { if(ans[i]==-1) { memset(book,0,sizeof book); res+=dfs(i); } } return res; } void init() { for(int i=0;i<n;i++){edge[i].clear();ans[i]=-1;} res=0; } int main() { int i,j; scanf("%d%d",&n,&m); init(); while(m--) { int x,y; scanf("%d%d",&x,&y); edge[x].push_back(y); edge[y].push_back(x); } printf("%d\n",XYL()); return 0; }
还有一种情况应该更大众吧,就是
左边的点和右边的点 分开编号给出,都从0或者1 开始编号。
这样子就不能一股脑的搜索了。有可能做题的人没有意识到,但是用上面的办法去做应该会很乱很扯....
而且我看到了 kuangbin大神的代码,一直没看懂。 后来自己想通了,很幸运发现和kuangbin大神的想法是一样的.....
题目例子是:
POJ 1469:http://poj.org/problem?id=1469 课程匹配问题。
因为题目已经分好了左边的点和右边的点。
所以对每个左边的点进行搜索。
去掉了判断这个点是不是没有匹配点。
因为,每个点起初都是没有匹配的。而当前点,是不可能被前面的点 给变成匹配点的。
这个判断也就显得多余。
这里面的两个数组:
book 表示
在每一次搜索中,右边的点有没有被 搜索过。
ans 表示
在整个过程中 ,
右边的点 对应的 匹配点!!
这个情况下的代码:(饿,是此题的代码)
#include"cstdio" #include"cstring" #include"vector" using namespace std; #define inf 999999999 #define loop(x,y,z) for(x=y;x<z;x++) int p,n,sum; int ans[309],book[309]; vector<int>edge[109]; void init() { sum=0; memset(ans,-1,sizeof ans); int i; loop(i,1,p+1)edge[i].clear(); } int dfs(int v) { int i,len; len=edge[v].size(); loop(i,0,len) { int u=edge[v][i]; if(!book[u]) { book[u]=1; if(ans[u]==-1||dfs(ans[u])) { ans[u]=v; re c4c9 turn 1; } } } return 0; } void XYL() { int i; loop(i,1,p+1) { memset(book,0,sizeof book); sum+=dfs(i); } } int main() { int i,j,T,k; scanf("%d",&T); while(T--) { scanf("%d%d",&p,&n); init(); loop(i,1,p+1) { scanf("%d",&j); while(j--) { scanf("%d",&k); edge[i].push_back(k); } } XYL(); if(sum==p) printf("YES\n"); else printf("NO\n"); } return 0; }[/code]
相关文章推荐
- hdu 1150 Machine Schedule(二分匹配,简单匈牙利算法)
- hdu 1150 Machine Schedule(二分匹配,简单匈牙利算法)
- 二分匹配(匈牙利算法)【模板】
- 二分匹配 ---- 匈牙利算法
- 关于匈牙利算法+二分匹配和KM算法的链接
- 匈牙利算法学习 (名词理解 + 简单说明)
- pku 1469 COURSES(二分匹配,匈牙利算法)
- hdu 2063 最大二分匹配,匈牙利算法
- 解题报告-HDOJ-2063(最大二分匹配-匈牙利算法)
- 关于匈牙利算法+二分匹配和KM算法的链接
- 最大二分匹配 匈牙利算法模板&&POJ 1469 COURSES
- POJ 2536 二分匹配 匈牙利算法 || 网络流
- 【二分匹配匈牙利算法模板】
- 匈牙利算法模板 图的二分匹配 hdu 2063 过山车
- 二分匹配匈牙利算法
- 二分图匹配匈牙利算法(poj1469验证)
- 二分匹配(匈牙利算法)
- poj 3041 二分匹配 基础题(整理版:基础知识)匈牙利算法
- 二分匹配总结(匈牙利算法+最大权+最小权)
- 二分匹配之匈牙利算法