java面试题算法(二)--匈牙利算法的应用

一.匈牙利算法解决的问题

       二分图的最大匹配数问题

二.匈牙利算法的应用场景示例

       一群男生与一群女生(二分图)参与相亲。你作为红娘牵线,希望通过你自己的努力,能让他们大多数人能找到终身的伴侣,当然越多越好(最大数),也能证明你的能力。当然看不对眼的不能硬凑,需要在看对眼(匹配)的情况下,帮助他们尽可能多的进行匹配。这个问题就是二分图的最大匹配数问题。

       预先定义的条件:男生和女生为1对,参与相亲的男生和女生都是单身

三.匈牙利算法的理解

 红娘让男生依次先找对象。

第一步,男生1看对眼了某女生1,此时最大匹配数为1。(要是谁都看不上,那红娘也帮不了你)

第二步,男生2找对象的时候此时会发生两种情况:

              第一种看上了某女生2,此时最大匹配数为2。这种情况比较简单

              第二种看上了女生1,这个时候男生2找到了男生1,这个时候又分两种情况:

                         1.男生1除了这个女孩1,其他一个都看不对眼,此时最大匹配数为1 (直接退出)

                         2.男生1和女孩2也看对眼了,这个时候红娘就让男生2就讨好男生1,这时候男生2就和女生1配对,男生1和女生2配对,此                           时最大匹配数为2

到这边可得出的结论是:最大匹配数为 当男生依次寻找对象时,初始为0,当后来的男生加入后,在能满足前面的男生的要求下,自己也找到了对象时,最大匹配数+1

第三步,与上述步骤类似,进行递归。需要注意的是,当女生曾试图改变过对象(包括,从没有对象转变为有对象和女生的对象进行改变),可能成功可能失败,无需再改变该女生的想法(要么已经成功(此时已经返回了),要么失败了(所以肯定是失败了))。

四.匈牙利算法代码实现

import java.util.Scanner;

public class Hungary {
	// boyNumber为男生数量 girlNumber为女生数量
	static int boyNumber, girlNumber;
	// line[boyIndex][girlIndex]=true 代表序号为boyIndex的男生,可和girlIndex女生适配
	static boolean[][] line = new boolean[100][100];
	// used[girlIndex]=true
	// 代表在一名男生寻找适配女生的过程中,girlIndex女生曾改变过对象(包括,从没有对象转变为有对象和女生的对象进行改变),可能成功可能失败。
	static boolean[] used = new boolean[100];
	// girl[girlIndex]中的值为女生当前的对象索引 -1为无对象
	static int[] girl = new int[100];

	public static void main(String[] args) {
		// 最大适配数
		int sum = 0;
		// 男女适配条数
		int fitNumber;
		Scanner sc = new Scanner(System.in);
		System.out.println("男生的数量为:");
		boyNumber = sc.nextInt();
		System.out.println("男生的数量为:"+boyNumber);
		System.out.println("女生的数量为:");
		girlNumber = sc.nextInt();
		System.out.println("女生的数量为:"+girlNumber);
		for (int i = 0; i < girlNumber; i++) {
			girl[i] = -1;
		}
		System.out.println("共有可适配条件数:");
		fitNumber = sc.nextInt();
		System.out.println("共有可适配条件数:"+fitNumber+"条");
		while (fitNumber-- > 0) {
			int tmp1 = sc.nextInt(), tmp2 = sc.nextInt();
			line[tmp1][tmp2] = true;
			System.out.println("男生"+tmp1+"女生"+tmp2+"可以配对");
		}
		for (int k = 0; k < boyNumber; k++) {
			// 清空 used数组,增加新的男生进行适配
			for (int l = 0; l < girlNumber; l++) {
				used[l] = false;
			}
			if (match(k)) {
				System.out.println("男生索引为"+k+"找得到对象");
				sum++;
			}
				
		}
		System.out.println("sum为"+sum);
		for (int m = 0;m < girlNumber; m++) {
			System.out.println(m+"女生配对男生: "+girl[m] );
		}
	}

	// 男生是否可以在现有情况下配对 boyIndex是男生的序号
	public static boolean match(int boyIndex) {
		// 匹配所有女生
		for (int girlIndex = 0; girlIndex < girlNumber; girlIndex++) {
			if (line[boyIndex][girlIndex] && used[girlIndex] == false) {
				used[girlIndex] = true;
				// 两种情况, 一该女生没男对象,二该女生可以换男对象(要成功)
				if (girl[girlIndex] == -1 || match(girl[girlIndex]))
					girl[girlIndex] = boyIndex;
					// 只有在这种情况下,匹配成功return true,其他均为false
					return true;
			}
		}
		return false;
	}
}

五.测试用例

4 4 (男生数量)

7 (适配条数)

0 0   (此条即以下为适配男生与女生索引,例如0号男生与0号女生看对眼了)

0 1

1 1

1 2

2 0

2 1

3 2

六.运行结果

男生索引为0找得到对象
男生索引为1找得到对象
男生索引为2找得到对象
sum为3
0女生配对男生: 2
1女生配对男生: 0
2女生配对男生: 1
3女生配对男生: -1 (-1代表该女生找不到对象。。。)

猜你喜欢

转载自blog.csdn.net/qq_41175067/article/details/81633213
今日推荐