复习2二分图匹配

我们现在讲下二分图匹配

1.什么是二分图

二分图又称作二部图,是图论中的一种特殊模型。 设(G=(V,E))是一个无向图,如果顶点(V)可分割为两个互不相交的子集((A,B)),并且图中的每条边((i,j))所关联的两个顶点i和j分别属于这两个不同的顶点集((iin A,jin B)),则称图(G)为一个二分图。

2.二分图的问题

我们来想一个比较浅显的问题,我们有(n)个男孩,(m)个女孩。每个男孩只愿意和一些他指定的女孩在一起,每个女孩也只希望和她指定的一些男孩在一起。当然同性肯定不能在一起(不就是lily和gay吗)当然肯定需要双方都同意才能在一起啊【手动滑稽】,此时我们现在想知道最多有多少对能成?

3.最佳二分图匹配(dinic)

我们可以用一个网络流算法来解这个问题
这里我们只需要建一个这样图,样例如下
输入格式:
第1行:n,m
第2~n+1行,第i行先是一个(B_i),然后是(B_i)个数,第j个数(x_j)表示第i个男生愿意和第(x_j)个女生在一起
第n+2~n+m+2行,第i行先是一个(G_i),然后是(G_i)个数,第j个数(y_j)表示第i个男生愿意和第(y_j)个女生在一起
输出格式:
一个整数表示最多的配对对数
样例输入:

3 3
1 1
2 1 2
3 1 2 3
2 1 2
2 1 3
1 3

样例输出:

2

这里写图片描述

现在我们就可以跑最大流了,最大流就是我们需要的答案

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>

#define Maxn 1000001
#define INF 0x7fffffff

using namespace std;

bool vis[1001][1001];

class Dinic{
    private:
        int n,s,t,w[Maxn],v[Maxn],next[Maxn],head[Maxn],cnt;
        int depth[Maxn];
        void add_edge(int x,int y,int z){
            next[++cnt]=head[x];
            v[cnt]=y;
            w[cnt]=z;
            head[x]=cnt;
            return;
        }
    public:
        void init(int x,int y,int z){
            n=x,s=y,t=z;
            cnt=-1;
            memset(head,-1,sizeof(head));
            memset(next,-1,sizeof(next));
            return;
        }
        void addedge(int x,int y,int z){
            add_edge(x,y,z);
            add_edge(y,x,0);
            return;
        }
        bool bfs(){
            queue<int>q;
            memset(depth,0,sizeof(depth));
            depth[s]=1;
            q.push(s);
            do{
                int u=q.front();
                q.pop();
                for(int i=head[u];~i;i=next[i]){
                    if(w[i]>0 and !depth[v[i]]){
                        depth[v[i]]=depth[u]+1;
                        q.push(v[i]);
                    }
                }
            }while(!q.empty());
            return depth[t];
        }
        int dfs(int u,int now){
            if(u==t)
                return now;
            for(int i=head[u];~i;i=next[i]){
                if(w[i]>0 and depth[v[i]]==depth[u]+1){
                    int d=dfs(v[i],min(now,w[i]));
                    if(d>0){
                        w[i]-=d;w[i^1]+=d;
                        return d;
                    }
                }
            }
            return 0;
        }
        int dinic(){
            int ans=0;
            while(bfs()){
                    ans+=dfs(s,INF);
            }
            return ans;
        }
}dinic;
int n,m,s,t;


int main(){
    scanf("%d%d",&n,&m);
    dinic.init(n,1,n+m+2); 
    for(int i=1;i<=n;i++){
    	int x;
    	scanf("%d",&x);
    	for(int j=1;j<=x;j++){
    		int y;
    		scanf("%d",&y);
    		vis[i][y]=1;
		}
		dinic.addedge(1,i+1,1);
	}
    for(int i=1;i<=m;i++){
    	int x;
    	scanf("%d",&x);
    	for(int j=1;j<=x;j++){
    		int y;
    		scanf("%d",&y);
    		if(vis[y][i]){
    			dinic.addedge(y+1,n+i+1,1);
			}
		}
		dinic.addedge(n+i+1,n+m+2,1);
	}
    printf("%d
",dinic.dinic());
    return 0;
}

4.我们再来看看匈牙利

匈牙利算法(Hungarian method)是由匈牙利数学家Edmonds于1965年提出,因而得名。匈牙利算法是基于Hall定理中充分性证明的思想,它是二分图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。

复杂度

时间复杂度邻接矩阵:最坏为(O(n^3)) 邻接表:(O(nm))
空间复杂度 邻接矩阵: (O(n^2)) 邻接表: (O(n+m))

思路

这就是匈牙利算法的流程,其中找妹子是个递归的过程,最最关键的字就是“腾”字

其原则大概是:有机会上,没机会创造机会也要上

代码

这是luogu模板P3386

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
bool f[1001][1001],vis[1001];
int n,m,e,ans,mat[1001]; 
bool dfs(int x){
    for(int i=1;i<=m;i++){
        if(f[x][i] and !vis[i]){
            vis[i]=1;
            if(!mat[i]){
                mat[i]=x;
                return 1;
            }else{
                if(dfs(mat[i])){
                    mat[i]=x;
                    return 1;
                }
            }
        }
    }
    return 0;
}

int main(){
    scanf("%d%d%d",&n,&m,&e);
    for(int i=1;i<=e;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        if(x<=n and y<=m)f[x][y]=1;
    }
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(dfs(i))ans++;
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/ezoihy/p/9368031.html