给定一个二分图,其中左半部包含n1n1个点(编号1~n1n1),右半部包含n2n2个点(编号1~n2n2),二分图共包含m条边。java
数据保证任意一条边的两个端点都不可能在同一部分中。算法
请你求出二分图的最大匹配数。spa
二分图的匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。code
二分图的最大匹配:全部匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。xml
第一行包含三个整数 n1n一、 n2n2 和 mm。blog
接下来m行,每行包含两个整数u和v,表示左半部点集中的点u和右半部点集中的点v之间存在一条边。class
输出一个整数,表示二分图的最大匹配数。import
1≤n1,n2≤5001≤n1,n2≤500,
1≤u≤n11≤u≤n1,
1≤v≤n21≤v≤n2,
1≤m≤1051≤m≤105im
2 2 4 1 1 1 2 2 1 2 2
时间复杂度O(mn) 实际运行时间通常远小于O(mn)
代码:2
//匈牙利算法 //思路:一个二分图,从左边子图最多能找到右边子图一一匹配的最大数量 //对于左边子图的某点,找右边子图的某点;若是右边连通的某点没有被匹配,那么能够选择该点做为匹配点; //不然,右边该点已经被匹配,则看看与右边的这个点匹配的左边的点可否还能找到另外一个匹配的右边的点, //若是能,则把右边这个点让给当前待匹配的左边的点 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); } }