稳定匹配算法是美国数学家 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 perferList;

// 配偶

private Girl pair;

public Boy(String iD, String name) {

super(iD, name);

this.perferList = new ArrayList<>();

}

public List getPerferList() {

return perferList;

}

public void setPerferList(List 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 boyLists; // 向其表白的男生

// 喜欢人员顺序列表

private List 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 getPerferList() {

return perferList;

}

public void setPerferList(List perferList) {

this.perferList = perferList;

}

public List getBoyLists() {

return boyLists;

}

public void setBoyLists(List 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 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 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 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 perferList = girl.getPerferList();//该女生喜欢列表

List 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());

}

n++;

}

System.out.println("最终结果:");

for (Boy boy : boys) {

System.out.println(boy.getName()+"->"+boy.getPair().getName());

}

}

// 选择最喜欢的男生

private static Human getMostLikeBoy(List boyLikes,List 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 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 boys) {

boolean flag = true;

for (Boy boy : boys) {

if (boy.getPair()==null) {

flag = false;

break;

}

}

return flag;

}

// 列表随机打乱

private static List shuffleGirls(List girls){

Random random = new Random();

List perferGirls = new ArrayList<>();

List 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 shuffleBoys(List boys){

Random random = new Random();

List perferBoys = new ArrayList<>();

List 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;

}

}

沙普利算法java实现_Java实现婚姻稳定匹配Gale- Shapley算法相关推荐

  1. 稳定婚姻问题:Gale–Shapley算法

    (一)问题的引出 在组合数学.经济学.计算机科学中,稳定婚姻问题(英语:stable marriage problem,简称SMP)又称为稳定配对问题(stable matching problem) ...

  2. 经典算法研究系列:图像特征提取与匹配之SIFT算法

     尺度不变特征转换(Scale-invariant feature transform 或 SIFT)是一种电脑视觉的算法用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置 ...

  3. ls算法java实现_Java API之算法 | 学步园

    本节中所描述的多态 排序(Sorting) 排序算法可为一个 List 重新排序,以使它的元素按照某种排序关系成上升式排序.有两种形式的操作被提供.简单形式的操作只采用一个 List 并按照它的元素的 ...

  4. 基于界面的银行家算法java实现_java实现银行家算法(Swing界面)

    java代码实现了银行家算法,界面写的个人认为还是较为细致的,完整的实现了找安全序列等算法功能,可作为参考学习银行家算法. 直接上代码:①界面展示方法: public void ShowFrame() ...

  5. 进程调度rr算法java实现_Java实现进程调度算法(二) RR(时间片轮转)

    一.概述 因为这次os作业对用户在控制台的输入输出有要求,所以我花了挺多的代码来完善控制台的显示. 也因为我这次要实现多个类似算法,所以将一些共性单独提取出来作为一个类. 如果只想要和算法有关的核心代 ...

  6. md5 算法java实现_java实现MD5算法

    import java.security.MessageDigest; /** 加密工具* @author 刘彦青 * **/ public class EncryptUtil { /** MD5加密 ...

  7. java常见排序算法有哪些_Java中常用的6种排序算法详细分解

    排序算法很多地方都会用到,近期又重新看了一遍算法,并自己简单地实现了一遍,特此记录下来,为以后复习留点材料. 废话不多说,下面逐一看看经典的排序算法: 1. 选择排序 选择排序的基本思想是遍历数组的过 ...

  8. 回文算法java实现_java算法题:最长回文串

    LeetCode: 给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串.在构造过程中,请注意区分大小写.比如"Aa"不能当做一个回文字符串.注 意:假设字 ...

  9. 【Java 虚拟机原理】垃圾回收算法 ( Java 虚拟机内存分区 | 垃圾回收机制 | 引用计数器算法 | 引用计数循环引用弊端 )

    文章目录 一.Java 虚拟机内存分区 二.垃圾回收机制 三.引用计数器算法 ( 无法解决循环引用问题 ) 一.Java 虚拟机内存分区 Java 虚拟机内存分区 : 所有线程共有的内存区域 : 堆 ...

  10. java 线性的排序算法_数据结构之排序算法Java实现(9)—— 线性排序之 基数排序算法...

    基数排序算法是计数排序的延伸,计数排序会造成很大的空间浪费,但基数排序法是对位数进行排序,适合于位数之间相差较大的情况,废话不多说,直接上代码: 升序排序法: /** * 基数排序法 * 升序排列 * ...

最新文章

  1. android 4.0(ICS)源码下载方法
  2. linux shell 获取字符串最后一个字符 去掉字符串最后一个字符 去掉末尾一个字符 去掉末尾两个字符
  3. C# 获取当前月第一天和最后一天 计算两个日期差多少天
  4. clockdiff-检测两台linux主机的时间差
  5. BAT会看上哪样的中小公司程序员?
  6. HDU 6264 Super-palindrome
  7. java ee maven_真正释放Maven和Java EE的强大功能
  8. 一企业靠数据中台打通SAP、ERP系统,还能做出可视化分析
  9. 编写超级可读代码的15个最佳实践
  10. PHP报错:Invalid body indentation level (expecting an indentation level of at least 4)
  11. Apache JMeter使用教程
  12. 火狐浏览器播放插件Linux,Firefox浏览器带flash播放器插件
  13. 【CG物理模拟系列】流体模拟--粒子法之MPS法(理论)
  14. pandas计算相关系数
  15. 三天打鱼两天晒网python程序_三天打鱼两天晒网
  16. 《新零售:低价高效的数据赋能之路》读后感
  17. 三分钟了解坚果J10的不足,多方位分析,让你学会挑选投影仪
  18. 离职后五险一金怎么办
  19. Windows .bat 脚本简单用法介绍
  20. 油气蒸汽发生器行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)

热门文章

  1. linux文件管理ppt,Linux操作系统_文件管理2.ppt
  2. c# TcpClient 客户端断线重连类库
  3. dep指定版本 go_Golang官方依赖管理工具:dep
  4. google gflags 库完全使用
  5. python 之 libtorrent库
  6. YYLabel使用笔记
  7. 【Jenkins】windows系统下Jenkins的下载、安装与启动
  8. jenkins插件下载加速
  9. Win10禁用UAC(用户账户控制)
  10. 如何保证虚拟机ip地址不变