二分图最大匹配

来源:互联网 发布:八爪鱼数据导出破解 编辑:程序博客网 时间:2024/05/22 05:49

讲解:

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;}


0 0
原创粉丝点击