一.理论准备
这两天看到了图论的二部图,闲着没事就水了一道。
先看增广路的定义:增广路,也称增广轨或交错轨:
若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。由增广路的定义可以推出下述三个结论:
无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。
- P的路径长度必定为奇数,第一条边和最后一条边都不属于M。
- 不断寻找增广路可以得到一个更大的匹配M’,直到找不到更多的增广路,M为G的最大匹配当且仅当不存在M的增广路径。
- 最大匹配数M+最大独立数N=总的结点数,增广路主要应用于匈牙利算法中,用于求二分图最大匹配。
二分图匹配可用匈牙利算法,离散中学过,就是找一条交替链,让路径的起点和终点都是还没有匹配过的点,路径经过的连线是一条没被匹配、一条已经匹配过,再下一条又没匹配这样交替地出现,显然路径里没被匹配的连线比已经匹配了的连线多一条,于是修改匹配图,把路径里所有匹配过的连线去掉匹配关系,把没有匹配的连线变成匹配的,这样匹配数就比原来多1个。不断执行上述操作,直到找不到这样的路径为止。
二.算法实现
以POJ1274为例直接去AC吧。
import java.util.Arrays;
import java.util.Scanner;
public class POJ1274 {/*
* 题意: n牛,m个房子,每个牛都只住在自己想住的房子里面,* 一个房子只能住一个牛,问最多可以安排多少头牛入住*/static boolean map[][];static boolean vis[];//记录匹配点号
static int path[];static int m,n;public static void main(String[] args) {Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
n = sc.nextInt();//n牛
m = sc.nextInt();//m屋
map = new boolean[n][m];int num;
for(int i=0; i<n; i++) {num = sc.nextInt();for(int j=0; j<num; j++) {int k = sc.nextInt();
map[i][k-1] = true;
}}int cnt = 0;
/*
* 表示牛棚和哪个牛配对*/path = new int[m];/*
* 由于牛编号从0开始,所以不能初始化为0* wa了几次*/Arrays.fill(path,-1);vis = new boolean[m];for(int i=0; i<n; i++) {Arrays.fill(vis,false);
if(find(i)) {
cnt++;}}System.out.println(cnt);}sc.close();}private static boolean find(int s) {for(int i=0; i<m; i++) {if(map[s][i] && vis[i]==false) {vis[i] = true;
/*
* /如果i未在前一个匹配M中 || i在匹配M中,但是从与i相邻的节点出发可以有增广路*/if(path[i]==-1 || find(path[i])) {
path[i] = s;return true;}}}return false;}}