【算法题】【51NOD】2006 飞行员配对(二分图最大匹配)
2018-08-05 本文已影响0人
Vinko_wei
题目描述
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员,其中1名是英国飞行员,另1名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空 军一次能派出最多的飞机 。对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案, 使皇家空军一次能派出最多的飞机。
Input
第1行有2个正整数 m 和 n。n 是皇家空军的飞行 员总数(n<100);m 是外籍飞行员数。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。输入最后以 2 个-1 结束。
Output
第 1 行是最佳飞行 员配对方案一次能派出的最多的飞机数 M。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。
Input示例
5 10
1 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1
Output示例
4
我的解题步骤
- 题目直接说明是二分图的最大匹配问题
- 去完善二分图的相关知识
- 再回来做题
下面一篇关于二分图最大匹配的文章(看过最好最易懂的文章)
本题代码
import java.util.Scanner;
public class Main {
static int n, m;
static int[][] conn; //已知的配合关系
static int[] people; //英国佬和外国佬的集合。 下标是编号; (people[i])是编号为i的对象的编号;
static int[] vis; //已访问
static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
input();
int num = 0; //最多可派出的飞机树
//为每一个外国佬找一个英国佬
for (int i = 1; i <= m ; i++) {
//初始化vis
resetVis();
if (find(i)) {
num ++;
}
}
System.out.println(num);
}
/*
* x : 外国佬在people数组里面的下标
* */
public static boolean find(int x) {
//遍历每一个英国佬
for (int i = m + 1; i <= n; i++) {
//检查当前的外国佬和英国佬的关系,和该英国佬是否被访问过
if (conn[x][i] == 1 && vis[i] == 0) {
//访问标记
vis[i] = 1;
//如果当前的英国佬还没对象匹配 或者 当前英国佬已经有对象了,但是英国佬可以搭档的对象不止一个可以找到下家。
if (people[i] == 0 || find(people[i])) {
//撮合英国佬i 和外国佬x
people[i] = x;
//匹配成功,返回true;
return true;
}
}
}
return false;
}
//获取输入的函数
public static void input() {
m = scanner.nextInt(); //外籍飞行员人数
n = scanner.nextInt(); //皇家飞行员人数
conn = new int[m + 1][n + 1];
people = new int[n + m + 1];
vis = new int[n + m + 1];
//获取关系
int x = 0, y = 0;
while (true) {
x = scanner.nextInt();
y = scanner.nextInt();
if (x == -1 || y == -1) {
break;
}
conn[x][y] = 1;
}
}
//重置Vis数组
public static void resetVis() {
for (int i = 1; i <= m+n; i++) {
vis[i] = 0;
}
}
}