您的位置:首页 > 其它

二分图最大匹配

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/
//#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: