原题链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2063
思路:
一开始用贪心做:按每一个女孩子期望搭档的人的数量将数组排序,然后优先选择期望数量少的,但是在oj上WA了(没想通为啥不行,有会的大佬还望指点/拜托)
然后就在网上看博客,看到大家都是用“匈牙利算法”做的,以前没听过,长知识了/捂脸
总结匈牙利算法本身:优先选择候选数据的第一个,然后能让就让——让的意思是自己选取下一个,将原来的腾给新的请求者,如果自己都没得选了,则不让(貌似也是贪心的思想?)
在网上找的博客地址:
https://blog.csdn.net/pku_coder/article/details/53701327
介绍完匈牙利算法,就讲讲在本题中如何应用的思路(其实这一题就是经典的匈牙利算法,都不用怎么变动的)
1.先将数据接收
- 创建一个used数组(用于在匈牙利算法中标记改人是否已经被查找过——也就是说选搭档的顺序只能顺着候选人往下,不能回头)
- 创建一个boy数组(用于记录每一次的搭档情况)
- 创建relation二维数组(用于存储女生期望搭档的映射图)
2.开始扫描每一个女生,每个女生都通过一次匈牙利算法,如果返回为true,这说明可以腾出位置,则结果加一,否则接着循环(注:在一个女生结束之后,将used数组回溯,便于下一次查找)
基本思路就是这样,也不知道说清楚没有/捂脸
下面直接上源码(附有原贪心WA算法):
package hduoj; import java.util.Scanner; ///** // * 使用贪心策略: // * 优先选择期望partner最少的 // */ //正解是使用匈牙利算法——最佳指配 public class hdoj_2063 { private static int[][] relation_pic; private static int[] used; private static int[] boy; private static int girl_num; private static int boy_num ; public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(true) { int count = sc.nextInt(); if (count == 0) break; girl_num = sc.nextInt(); boy_num = sc.nextInt(); relation_pic = new int[girl_num + 1][boy_num + 1]; used = new int[boy_num + 1]; boy = new int[boy_num + 1]; while (count-- != 0) { int girl_no = sc.nextInt(); int boy_no = sc.nextInt(); relation_pic[girl_no][boy_no] = 1; } int res = 0; for(int i = 1;i<=girl_num;++i){ for(int j = 1;j<=boy_num;++j){ used[j] = 0;//将男同学恢复单身 } if(find(i)){ res++; } } System.out.println(res); } } private static boolean find(int girl_no){ for(int i = 1;i <= boy_num;++i){//扫描每个男生 if(relation_pic[girl_no][i]==1&&used[i]==0){ //若当前有暧昧关系且男生未被标记的话,则让其标记为已查找过 used[i] = 1; if(boy[i] == 0 || find(boy[i])){ //若当前男生无搭档或者其搭档可以重新分配给别人的话,则返回true,表示找到新的分配组合 boy[i] = girl_no; return true; } } } return false; } //贪心做法失败 // public static void main(String[] args) { // Scanner sc = new Scanner(System.in); // while(true){ // int count = sc.nextInt(); // if(count == 0) break; // int boy_num = sc.nextInt(); // int girl_num = sc.nextInt(); // Integer[][] combination = new Integer[girl_num + 1][]; // // int[] boy_flag = new int[boy_num + 1]; // for(int i = 0;i<=boy_num;++i){//用来标记已经被选中的男孩,0为被选中 // boy_flag[i] = 1; // } // HashMap<Integer,ArrayList<Integer>> hashmap = new HashMap<>(); // for(int i = 0;i<count;++i){ // int girl = sc.nextInt(); // int boy = sc.nextInt(); // if(hashmap.containsKey(girl)){ // hashmap.get(girl).add(boy); // }else{ // hashmap.put(girl,new ArrayList<Integer>()); // hashmap.get(girl).add(Integer.valueOf(boy)); // } // }//初始化 // // for(Integer each:hashmap.keySet()){ // Integer[] temp = {}; // temp = hashmap.get(each).toArray(temp); // combination[each] = temp; // } // int res = 0; // // // sort_by_length(combination);//通过每一行长度进行冒泡排序 // // for(int i = 1;i<combination.length;++i){ // for(int j = 0;j<combination[i].length;++j){ // if(boy_flag[combination[i][j]]==1){ // res++; // boy_flag[combination[i][j]] = 0; // } // } // } // System.out.println(res); // // } // } // // private static void sort_by_length(Integer[][] arr){ // boolean flag = false; // for(int i = 1;i<= arr.length;++i){ // for(int j = 2;j <= arr.length - i;++j){ // if(arr[j].length < arr[j-1].length){ // Integer[] temp = arr[j]; // arr[j] = arr[j-1]; // arr[j-1] = temp; // flag = true; // } // } // if(!flag){ // break; // } // } // } }
代码已经ac
希望对大家有所帮助
以上