Java实现婚姻稳定匹配Gale- Shapley算法
稳定匹配算法是美国数学家 David Gale 和 Lloyd Shapley在1962年提出的一种寻找稳定婚姻的策略。这种匹配方式的特点在于:不管需要匹配的总人数有多少、不管他们各自的偏好如何,只要男女人数相等,并且男女双方每个人都能在心中给对方打分,那么应用这种策略后总能得到一个稳定的婚姻搭配。
有N男N女需要寻找结婚对象,并假设他们的性取向全部正常——即婚姻的搭配方式只有男&女这一种。要求是帮助这N男N女中的每个人都成功匹配一个婚姻的对象,并且这个对象必须是稳定的。
什么是稳定呢?举个例子说明:假设有两对夫妻M1&F2、M2&F1。M1心中更喜欢F1,但是他和F2结婚了,M2心目中更喜欢F2,但是他和F1结婚了,显然这样的婚姻是不稳定的,因为随时都可能发生M1和F1私奔或者M2和F2私奔的情况(当然,在这里我们需要假设情感因素是婚姻绝对的主导,虽然这在生活中基本不存在,但是在数学世界中我们不妨就这么假设)。所以在男女双方做匹配时(也就是结婚的时候)需要做出稳定的选择,以防这种情况的发生。
盖尔-沙普利(Gale-Shapley)稳定匹配算法解决了这一问题,它的思路如下。
首先,男生需要按照希望与之交往的顺序给所有女生排序,即最理想的女友排在最前、最不理想的放在最后。同样,每个女生也需要给男生排序。接着,男生将按照自己的名单一轮一轮地去追求喜欢的女生,女生也将按照自己的名单接受或拒绝对方的追求。
第一轮,每个男生都向自己名单上排在首位的女生表白。此时,一个女生可能面对的情况有三种:没有人跟她表白、只有一人跟她表白、有不止一人跟她表白。在第一种情况下,这个女生什么都不做,继续等待即可;在第二种情况下,女生接受那个人的表白,答应暂时和他做男女朋友;在第三种情况下,女生从所有追求者中选择自己最喜欢的那一位,答应和他暂时做男女朋友,并拒绝其他所有的追求者。
第一轮结束后,有些男生已经有女朋友了而有些男生仍然是单身。在第二轮表白行动中,每个单身男都会从所有还没拒绝过自己的女生中选出自己最喜欢的那一个,并向她表白,不管她现在是否是单身。和第一轮一样,每个被表白的女生需要从表白者中选择最喜欢的男生,并拒绝其他追求者。注意,如果这个女生当前已经有男朋友了,当她遇到了更好的追求者时,她将毫不犹豫地和现男友分手,投向新追求者的怀抱。这样以来,一些单身男生将脱单,而一些男生也会被分手,重新进入单身男生的行列。
在以后的每一轮中,单身男生们将发扬愈挫愈勇的顽强精神,继续追求列表中的下一个女生;女生则从包括现男友在内的所有追求者中选择最好的一个,并给其他所有追求者发好人卡。这样一轮一轮地进行下去,直到某个时刻所有人都不再单身,那么下一轮将不会有任何新的表白,每个人的对象也都将固定下来,整个过程结束——此时的搭配就一定是稳定的了。
代码实现:
package com.galeshaple;
public class Human {
// 唯一ID
private String ID;
// 姓名
private String name;
public Human() {
}
public Human(String iD, String name) {
super();
ID = iD;
this.name = name;
}
public String getID() {
return ID;
}
public void setID(String iD) {
ID = iD;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.galeshaple;
import java.util.ArrayList;
import java.util.List;
public class Boy extends Human {
// 喜欢人员顺序列表
private List<Girl> perferList;
// 配偶
private Girl pair;
public Boy(String iD, String name) {
super(iD, name);
this.perferList = new ArrayList<>();
}
public List<Girl> getPerferList() {
return perferList;
}
public void setPerferList(List<Girl> perferList) {
this.perferList = perferList;
}
public Girl getPair() {
return pair;
}
public void setPair(Girl pair) {
this.pair = pair;
}
}
package com.galeshaple;
import java.util.ArrayList;
import java.util.List;
public class Girl extends Human {
private List<Boy> boyLists; // 向其表白的男生
// 喜欢人员顺序列表
private List<Boy> perferList;
// 配偶
private Boy pair;
public Girl() {
super();
}
public Girl(String iD, String name) {
super(iD, name);
this.boyLists = new ArrayList<>();
this.perferList = new ArrayList<>();
}
public List<Boy> getPerferList() {
return perferList;
}
public void setPerferList(List<Boy> perferList) {
this.perferList = perferList;
}
public List<Boy> getBoyLists() {
return boyLists;
}
public void setBoyLists(List<Boy> boyLists) {
this.boyLists = boyLists;
}
public Boy getPair() {
return pair;
}
public void setPair(Boy pair) {
this.pair = pair;
}
// 分手
public void divided() {
System.out.println(this.getName() + "和" + this.getPair().getName() + "分手");
this.getPair().getPerferList().remove(this);
this.getPair().setPair(null);
this.setPair(null);
}
// 决绝所有表白男生
public void rejectBoys(List<Boy> boyList) {
for (Boy boy : boyList) {
boy.getPerferList().remove(this);
}
}
// 选择最喜欢的,拒绝其他的
}
package com.galeshaple;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Main {
public static void main(String[] args) {
// 实例化10个男生
Boy boy1 = new Boy("Man01", "李明");
Boy boy2 = new Boy("Man02", "张磊");
Boy boy3 = new Boy("Man03", "吴刚");
Boy boy4 = new Boy("Man04", "刘杰");
Boy boy5 = new Boy("Man05", "王浩");
Boy boy6 = new Boy("Man06", "赵宇");
Boy boy7 = new Boy("Man07", "钱江");
Boy boy8 = new Boy("Man08", "孙立");
Boy boy9 = new Boy("Man09", "周强");
Boy boy10 = new Boy("Man10", "郑智");
// 实例化10个女生
Girl girl1 = new Girl("Girl1", "朵朵");
Girl girl2 = new Girl("Girl2", "谷谷");
Girl girl3 = new Girl("Girl3", "丽丽");
Girl girl4 = new Girl("Girl4", "萌萌");
Girl girl5 = new Girl("Girl5", "佳佳");
Girl girl6 = new Girl("Girl6", "依依");
Girl girl7 = new Girl("Girl7", "妮妮");
Girl girl8 = new Girl("Girl8", "安安");
Girl girl9 = new Girl("Girl9", "米米");
Girl girl10 = new Girl("Girl10", "露露");
List<Girl> girls = new ArrayList<>();
girls.add(girl1);
girls.add(girl2);
girls.add(girl3);
girls.add(girl4);
girls.add(girl5);
girls.add(girl6);
girls.add(girl7);
girls.add(girl8);
girls.add(girl9);
girls.add(girl10);
List<Boy> boys = new ArrayList<>();
boys.add(boy1);
boys.add(boy2);
boys.add(boy3);
boys.add(boy4);
boys.add(boy5);
boys.add(boy6);
boys.add(boy7);
boys.add(boy8);
boys.add(boy9);
boys.add(boy10);
// 初始化 随机喜欢序列
for (Boy boy : boys) {
boy.setPerferList(shuffleGirls(girls));
}
for (Girl girl : girls) {
girl.setPerferList(shuffleBoys(boys));
}
// 循环,直到最终匹配
int n = 1;// 轮数
while (!isAllPaired(boys)) {
System.out.println("第"+n+"轮匹配:");
// 所有没有对象的男生向女生表白
for (Boy boy : boys) {
if (boy.getPair()==null) {
// 要表白的女生
Girl girl = boy.getPerferList().get(0);
// 加入该女生的表白男生序列
girl.getBoyLists().add(boy);
System.out.println(boy.getName()+"向"+girl.getName()+"表白");
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 对于所有的女生
for (Girl girl : girls) {
List<Boy> perferList = girl.getPerferList();//该女生喜欢列表
List<Boy> boyLists = girl.getBoyLists();// 向其表白的男生列表
// 选择最喜欢的并拒绝其他的
if (boyLists!=null&&(boyLists.size()>0)) {
Boy mostLikeBoy = (Boy) getMostLikeBoy(boyLists, perferList);
// 如果女生有对象,则重新选择
if (girl.getPair()!=null) {
Boy girsPair = (Boy) girl.getPair();
int mostLikeBoyIndex = getBoyLikeIndex(mostLikeBoy, perferList);
int girsPairIndex = getBoyLikeIndex(girsPair, perferList);
if (mostLikeBoyIndex>girsPairIndex) {
// 保持现有,拒绝所有表白者
girl.rejectBoys(boyLists);
for (Boy boy : boyLists) {
System.out.println(girl.getName()+"拒绝了"+boy.getName());
}
}else {
// 分手,选择最喜欢的
girl.divided();
girl.setPair(mostLikeBoy);
mostLikeBoy.setPair(girl);
}
}else {
// 选择最喜欢的,拒绝其他的
girl.setPair(mostLikeBoy);
mostLikeBoy.setPair(girl);
System.out.println(girl.getName()+"和"+mostLikeBoy.getName()+"匹配成功");
boyLists.remove(mostLikeBoy);
girl.rejectBoys(boyLists);
for (Boy boy : boyLists) {
System.out.println(girl.getName()+"拒绝了"+boy.getName());
}
}
}
girl.setBoyLists(new ArrayList<Boy>());
}
n++;
}
System.out.println("最终结果:");
for (Boy boy : boys) {
System.out.println(boy.getName()+"->"+boy.getPair().getName());
}
}
// 选择最喜欢的男生
private static Human getMostLikeBoy(List<Boy> boyLikes,List<Boy> perferList){
Human human;
int index=10000000;
for (Human boy : boyLikes) {
if (index>getBoyLikeIndex((Boy) boy, perferList)){
index = getBoyLikeIndex((Boy) boy, perferList);
};
}
human = perferList.get(index);
return human;
}
// 获取表白男生喜欢排名
private static int getBoyLikeIndex(Boy boy,List<Boy> boys) {
int flag = 0;
for (int i = 0; i < boys.size(); i++) {
if (boy.getID().equals(boys.get(i).getID())) {
flag = i;
}
}
return flag;
}
// 判断是否最终匹配,即每个男生都有对象
private static boolean isAllPaired(List<Boy> boys) {
boolean flag = true;
for (Boy boy : boys) {
if (boy.getPair()==null) {
flag = false;
break;
}
}
return flag;
}
// 列表随机打乱
private static List<Girl> shuffleGirls(List<Girl> girls){
Random random = new Random();
List<Girl> perferGirls = new ArrayList<>();
List<Girl> perferTempGirls = new ArrayList<>();
for (int i = 0; i < girls.size(); i++) {
perferTempGirls.add(girls.get(i));
}
while (perferTempGirls.size()>0) {
int randomPos = random.nextInt(perferTempGirls.size());
perferGirls.add(perferTempGirls.get(randomPos));
perferTempGirls.remove(randomPos);
}
return perferGirls;
}
private static List<Boy> shuffleBoys(List<Boy> boys){
Random random = new Random();
List<Boy> perferBoys = new ArrayList<>();
List<Boy> perferTempBoys = new ArrayList<>();
for (int i = 0; i < boys.size(); i++) {
perferTempBoys.add(boys.get(i));
}
while (perferTempBoys.size()>0) {
int randomPos = random.nextInt(perferTempBoys.size());
perferBoys.add(perferTempBoys.get(randomPos));
perferTempBoys.remove(randomPos);
}
return perferBoys;
}
}

浙公网安备 33010602011771号