二分图最大匹配

一.理论准备

        这两天看到了图论的二部图,闲着没事就水了一道。

        先看增广路的定义:增广路,也称增广轨或交错轨:
若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。

        由增广路的定义可以推出下述三个结论:

  1. P的路径长度必定为奇数,第一条边和最后一条边都不属于M。
  2. 不断寻找增广路可以得到一个更大的匹配M’,直到找不到更多的增广路,M为G的最大匹配当且仅当不存在M的增广路径。
  3. 最大匹配数M+最大独立数N=总的结点数,增广路主要应用于匈牙利算法中,用于求二分图最大匹配。    
        无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。

        二分图匹配可用匈牙利算法,离散中学过,就是找一条交替链,让路径的起点和终点都是还没有匹配过的点,路径经过的连线是一条没被匹配、一条已经匹配过,再下一条又没匹配这样交替地出现,显然路径里没被匹配的连线比已经匹配了的连线多一条,于是修改匹配图,把路径里所有匹配过的连线去掉匹配关系,把没有匹配的连线变成匹配的,这样匹配数就比原来多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;
  }
}

你可能感兴趣的:(二分图)