zoukankan      html  css  js  c++  java
  • 二分图最大匹配

    二分图最大匹配

    Posted on 2013-08-15 14:13 DM张朋飞 阅读(167) 评论(0编辑 收藏

    一.理论准备

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

            先看增广路的定义:增广路,也称增广轨或交错轨: 
    若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;
    
      }
    
    }
    
    作者:张朋飞
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
     
    分类: POJGraphAlgorithm
  • 相关阅读:
    第六章 (3)CreateThread函数
    第六章(5)C/C++运行期库
    自己去除迅雷广告
    第六章(4)终止线程的运行
    第四章 进程(7)CreateProcess函数详解
    第六章(6)进程ID的相关函数
    第六章 线程的基础知识
    第四章 进程(5)进程的当前驱动器和目录
    第四章 进程(6)CreateProcess函数详解
    第六章 (2)线程函数
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3260225.html
Copyright © 2011-2022 走看看