菜鸟系列——二分图匹配
2015-07-25 17:04
204 查看
菜鸟就要老老实实重新学起:
二分图匹配——匈牙利算法(dfs实现)
dfs深搜找增广路经求二分图最大匹配。//二分图匹配:二分图最大配对数 //最小点覆盖:选取最少的点覆盖所有边 //最大独立集:选取最多的点,集合中点之间无连接 //二分图最大匹配==最小点覆盖==总点数-最大独立集
模版:
#define N 1234 int n,m,cnt; int f ; int vm ,um ; bool vis ; vector<int>g ; void init() { cnt = 0; memset(f,-1,sizeof(f)); memset(vm,-1,sizeof(vm)); memset(um,-1,sizeof(um)); for(int i=0;i<=n+m;i++) g[i].clear(); } void inserts(int u, int v) { g[u].push_back(v); g[v].push_back(u); } int dfs(int u) { int v; for(int i=0;i<g[u].size();i++) { v = g[u][i]; if(vis[v]) continue; vis[v] = 1; //能直接找到增广路径或者连接该节点的节点有其他增广路径 if(vm[v] == -1 || dfs(vm[v])!=-1) { vm[v] = u; um[u] = v; return v; } } return -1; } //染色 void dye(int u) { int v; for(int i=0;i<g[u].size();i++) { v = g[u][i]; if(f[v]!=-1) continue; f[v] = f[u]^1; dye(v); } } void Dye() { for(int i=1;i<=n;i++) if(f[i] == -1) { f[i] = 0; dye(i); } } int maxMatch() { Dye(); int res = 0; for(int i=1;i<=n;i++) if(!f[i]) { memset(vis,0,sizeof(vis)); if(dfs(i)!=-1) res++; } //取得最大点集覆盖 return res; }
二分图匹配——Hopcroft-Karp算法
就是先通过BFS找到增广路径集,用来更新匹配值,在点数较多时有不错的时间表现。模版:
#define N 51234 vector<int>g ; int um ,vm ,n; int dx ,dy ,dis; bool vis ; void inserts(int u, int v) { g[u].push_back(v); } bool searchP() { queue<int>q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=1;i<=n;i++) if(um[i]==-1) { q.push(i); dx[i]=0; } while(!q.empty()) { int u=q.front();q.pop(); if(dx[u]>dis) break; for(int i=0;i<g[u].size();i++) { int v = g[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(vm[v]==-1) dis=dy[v]; else { dx[vm[v]]=dy[v]+1; q.push(vm[v]); } } } } return dis!=INF; } bool dfs(int u) { for(int i=0;i<g[u].size();i++) { int v = g[u][i]; if(!vis[v]&&dy[v]==dx[u]+1) { vis[v]=1; if(vm[v]!=-1&&dy[v]==dis) continue; if(vm[v]==-1||dfs(vm[v])) { vm[v]=u;um[u]=v; return 1; } } } return 0; } int maxMatch() { int res=0; memset(um,-1,sizeof(um)); memset(vm,-1,sizeof(vm)); while(searchP()) { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) if(um[i]==-1&&dfs(i)) res++; } return res; }
eg:
POJ1274 The Perfect Stall
http://poj.org/problem?id=1274题意:
n个奶牛,m个谷仓,奶牛有自己喜欢的谷仓。求最多有多少头牛能去自己喜欢的谷仓。
思路:
奶牛与谷仓即为二分图,匈牙利算法求最大匹配即可;code:
#define N 1234 int n,m,cnt; int f ; int vm ,um ; bool vis ; vector<int>g ; void init() { cnt = 0; memset(f,-1,sizeof(f)); memset(vm,-1,sizeof(vm)); memset(um,-1,sizeof(um)); for(int i=0;i<=n+m;i++) g[i].clear(); } void inserts(int u, int v) { g[u].push_back(v); g[v].push_back(u); } int dfs(int u) { int v; for(int i=0;i<g[u].size();i++) { v = g[u][i]; if(vis[v]) continue; vis[v] = 1; if(vm[v] == -1 || dfs(vm[v])!=-1) { vm[v] = u; um[u] = v; return v; } } return -1; } int maxMatch() { int res = 0; for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(dfs(i)!=-1) res++; } return res; } int main() { int i,j,k,kk,t,x,y; while(scanf("%d%d",&n,&m)!=EOF&&n) { init(); for(i=0;i<n;i++) { scanf("%d",&t); for(j=0;j<t;j++) { scanf("%d",&y); inserts(i+1,y+n); } } printf("%d\n",maxMatch()); } return 0; }
相关文章推荐
- 用jdbc向数据库插入数据后获取生成的主键值
- 跳跃的字符(简单)
- 安卓开发笔记——高仿新浪微博文字处理(实现关键字高亮,自定义表情替换并加入点击事件实现)
- 实用软件程序包包含的头文件
- 数组作为实参和形参的形式是怎样的?zhidao.baidu.com/link?url=owojlL0OUiAYU50L9g86kmo5AToWjv42ZQo9WN0HhtvHzGbcU7etRbJ69
- HDU_1501_Zipper
- hdu2203 KMP水的问题
- 计算所有数字的和(中等)
- [leetcode] 215.
- VS开发平台的生成后事件
- glVertexAttribPointer参数意义说明
- Codeforces 301_div.2_Ice Cave(BFS走冰块)
- 深入理解Java对象序列化
- 編程之美2.9:神奇的菲波那契數列
- javascript页面倒计时实例
- 数的双亲表示法结点结构定义
- poj 2886
- POJ 3255 Roadblocks
- 5. openCV中常用函数学习
- 吃甘蔗(中等,模拟)