给定一个二分图,其中左半部包含n1n1个点(编号1~n1n1),右半部包含n2n2个点(编号1~n2n2),二分图共包含m条边。
数据保证任意一条边的两个端点都不可能在同一部分中。
请你求出二分图的最大匹配数。
二分图的匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。
输入格式
第一行包含三个整数 n1n1、 n2n2 和 mm。
接下来m行,每行包含两个整数u和v,表示左半部点集中的点u和右半部点集中的点v之间存在一条边。
输出格式
输出一个整数,表示二分图的最大匹配数。
数据范围
1≤n1,n2≤5001≤n1,n2≤500,
1≤u≤n11≤u≤n1,
1≤v≤n21≤v≤n2,
1≤m≤1051≤m≤105
输入样例:
2 2 4
1 1
1 2
2 1
2 2
输出样例:
2
时间复杂度O(mn) 实际运行时间一般远小于O(mn)
代码:
//匈牙利算法 //思路:一个二分图,从左边子图最多能找到右边子图一一匹配的最大数量 //对于左边子图的某点,找右边子图的某点;如果右边连通的某点没有被匹配,那么可以选择该点作为匹配点; //否则,右边该点已经被匹配,则看看与右边的这个点匹配的左边的点能否还能找到另一个匹配的右边的点, //如果能,则把右边这个点让给当前待匹配的左边的点 import java.util.Arrays; import java.util.Scanner; public class Main{ static final int N=505,M=100005; static int h[]=new int[N]; static int e[]=new int[M]; static int ne[]=new int[M]; static int n1,n2,m,idx; static int match[]=new int[N]; static boolean vis[]=new boolean[N]; static void add(int a,int b){ e[idx]=b; ne[idx]=h[a]; h[a]=idx++; } static boolean find(int u){ for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(!vis[j]){ vis[j]=true; if(match[j]==0 || find(match[j])){//右边的该点没有被匹配或者j对应的左边的点能找到另一个能匹配的右边的点 match[j]=u; return true; } } } return false; } public static void main(String[] args) { Scanner scan=new Scanner(System.in); Arrays.fill(h, -1); n1=scan.nextInt(); n2=scan.nextInt(); m=scan.nextInt(); while(m-->0){ int a=scan.nextInt(); int b=scan.nextInt(); add(a,b);//我们只从左边向右边查找 } int res=0; for(int i=1;i<=n1;i++){ Arrays.fill(vis, false);//初始化,对于每一个左边的点,一开始它都没有匹配右边的点 if(find(i)) res++; } System.out.println(res); } }