二分图最大匹配
2015-08-25 20:23
525 查看
讲解:
http://www.renfei.org/blog/bipartite-matching.html
(该博客最大独立集)
补充定义和定理:
最大匹配数:最大匹配的匹配边的数目
最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
最大独立数:选取最多的点,使任意所选两点均不相连
最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。
定理1:最大匹配数 = 最小点覆盖数(这是 Konig 定理)
定理2:最大独立数 = 顶点数 - 最大匹配数
定理3:最小路径覆盖数 = 顶点数 - 最大匹配数
手工模板:
http://paste.ubuntu.com/12192113/
http://www.renfei.org/blog/bipartite-matching.html
(该博客最大独立集)
补充定义和定理:
最大匹配数:最大匹配的匹配边的数目
最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
最大独立数:选取最多的点,使任意所选两点均不相连
最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。
定理1:最大匹配数 = 最小点覆盖数(这是 Konig 定理)
定理2:最大独立数 = 顶点数 - 最大匹配数
定理3:最小路径覆盖数 = 顶点数 - 最大匹配数
手工模板:
http://paste.ubuntu.com/12192113/
//#include<bits/stdc++.h> #include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <string> #include <vector> #include <cmath> #include <map> #include <queue> #include <stack> #include <set> #include <algorithm> using namespace std; #define For(i,a,b) for(int (i)=(a);(i) < (b);(i)++) #define rof(i,a,b) for(int (i)=(a);(i) > (b);(i)--) #define IOS ios::sync_with_stdio(false) #define lson l,m,rt <<1 #define rson m+1,r,rt<<1|1 #define mem(a,b) memset(a,b,sizeof(a)) typedef long long ll; typedef unsigned long long ull; void RI (int& x){ x = 0; char c = getchar (); while (c == ' '||c == '\n') c = getchar (); bool flag = 1; if (c == '-'){ flag = 0; c = getchar (); } while (c >= '0' && c <= '9'){ x = x * 10 + c - '0'; c = getchar (); } if (!flag) x = -x; } void RII (int& x, int& y){RI (x), RI (y);} void RIII (int& x, int& y, int& z){RI (x), RI (y), RI (z);} /**************************************END define***************************************/ const int maxn = 2e3+10;//单侧顶点最大数目 const int INF =0x3f3f3f3f; const int maxm = 2e4+10; struct Side { int from,to,next; }; struct BPM{ int n,m; //左右n,m个点 Side side[maxm]; int top; int node[maxn]; int left[maxn]; // left[i]为右边第i个点的匹配点编号,-1表示不存在 bool T[maxn]; // T[i]为右边第i个点是否已标记 /*求最小覆盖点集时用 int right[maxn]; // right[i]为左边第i个点的匹配点编号,-1表示不存在 bool S[maxn]; //左边第i个点,被标记为true时:为未盖点 */ void init(int nn,int mm) { n=nn,m=mm; top=0; mem(node,-1); } void add_side(int u,int v) { side[top]=(Side){u,v,node[u]}; node[u]=top++; } bool dfs(int u){ /*S[u]=true;*/ for(int i=node[u];i!=-1;i=side[i].next){ int v=side[i].to; if(!T[v]){ T[v]=true; if(left[v]==-1||dfs(left[v])){ left[v]=u; /*right[u]=v;*/ return true; } } } return false; } //求最大匹配,匈牙利算法 int hungarian() { int ans=0; mem(left,-1); /*mem(right,-1);*/ // u 范围为0~n-1 for(int u=0;u<n;u++){ /*mem(S,0);*/ mem(T,0); if(dfs(u)) ans++; } return ans; } /* //求最小覆盖。X和Y为最小覆盖中的点集 int mincover(vector<int>& X,vector<int>& Y){ int ans=hungarian(); mem(S,0); mem(T,0); for(int u=0;u<n;u++) if(right[u]==-1) dfs(u);// 从所有X未盖点出发增广 for(int u=0;u<n;u++) if(!S[u]) X.push_back(u);//S[u]为false为匹配点 for(int v=0;v<m;v++) if(T[v])Y.push_back(v);//T[u]为true为匹配点 return ans; } */ }; BPM solver; int main() { freopen("input.txt","r",stdin); int n,m; while(~scanf("%d%d",&n,&m)){ solver.init(n,n); while(m--){ int x,y; RII(x,y); x--;y--; solver.add_side(x,y); } int ans=solver.hungarian(); printf("%d\n",ans); } return 0; }
相关文章推荐
- HashMap的两种排序方式
- java框架篇---struts之OGNL详解
- 支持向量机之线性支持向量机(三)
- VLAD局部特征聚合描述符
- CRF技能词识别过程
- bootstrap-js(5)工具提示tooltip
- Java Servlet完全教程
- struct和typedef struct分析
- MySQL合理利用锁机制优化
- mac在下面Apache 创 .htaccess档
- 事件机制实现超时触发功能,同时捕捉Ctrl+C信号
- UML总结(对九种图的认识和如何使用Rational Rose 画图)
- java多线程之三
- cookie 和session 的区别详解
- 简单原理来介绍java编程之反射
- java综合(二)springmvc与spring整合
- Android笔记 4
- 数据库存储过程
- Java并发编程:Lock
- 2015/08/25