Gale-Shapley算法

news2024/12/22 6:19:49

一. 设计目的

盖尔-沙普利算法(Gale-Shapley算法)的设计目的是为了解决稳定匹配问题,即在给定一组男性和女性的偏好列表的情况下,找到一个稳定的匹配。这里的“稳定”指的是不存在任何一对男性和女性,他们彼此都比当前的匹配对象更偏好对方,从而可能破坏现有的匹配。

二. 设计内容

2.1 背景说明

盖尔-沙普利(Gale-Shapley)稳定匹配算法是美国数学家 David Gale 和 Lloyd Shapley在1962年提出的一种寻找稳定婚姻的策略。这种匹配方式的特点在于:不管需要匹配的总人数有多少、不管他们各自的偏好如何,只要男女人数相等,并且男女双方每个人都能在心中给对方打分,那么应用这种策略后总能得到一个稳定的婚姻搭配。换句话说,他们证明了稳定的婚姻搭配总是存在的。并且这种策略反映了现实生活中的很多真实情况,也不仅仅局限于婚姻匹配。

2.2 问题描述

有N男N女需要寻找结婚对象,并假设他们的性取向全部正常——即婚姻的搭配方式只有男&女这一种。要求是帮助这N男N女中的每个人都成功匹配一个婚姻的对象,并且这个对象必须是稳定的。

什么是稳定呢?举个例子说明:

假设有两对夫妻M1&F2、M2&F1。M1心中更喜欢F1,但是他和F2结婚了,M2心目中更喜欢F2,但是他和F1结婚了,显然这样的婚姻是不稳定的,因为随时都可能发生M1和F1私奔或者M2和F2私奔的情况。所以在男女双方做匹配时(也就是结婚的时候)需要做出稳定的选择,以防这种情况的发生。

三. 步骤

首先,男生需要按照希望与之交往的顺序给所有女生排序,即最理想的女友排在最前、最不理想的放在最后。同样,每个女生也需要给男生排序。接着,男生将按照自己的名单一轮一轮地去追求喜欢的女生,女生也将按照自己的名单接受或拒绝对方的追求。

第一轮,每个男生都向自己名单上排在首位的女生表白。此时,一个女生可能面对的情况有三种:没有人跟她表白、只有一人跟她表白、有不止一人跟她表白。在第一种情况下,这个女生什么都不做,继续等待即可;在第二种情况下,女生接受那个人的表白,答应暂时和他做男女朋友;在第三种情况下,女生从所有追求者中选择自己最喜欢的那一位,答应和他暂时做男女朋友,并拒绝其他所有的追求者。

第一轮结束后,有些男生已经有女朋友了而有些男生仍然是单身狗。在第二轮表白行动中,每个单身男都会从所有还没拒绝过自己的女生中选出自己最喜欢的那一个,并向她表白,不管她现在是否是单身。和第一轮一样,每个被表白的女生需要从表白者中选择最喜欢的男生,并拒绝其他追求者。注意,如果这个女生当前已经有男朋友了,当她遇到了更好的追求者时,她将毫不犹豫地和现男友分手,投向新追求者的怀抱。这样以来,一些单身狗将脱单,而一些倒霉的恩爱狗(男)也会被分手,重新进入单身狗的行列。

在以后的每一轮中,单身狗们将发扬愈挫愈勇的顽强精神,继续追求列表中的下一个女生;女生则从包括现男友在内的所有追求者中选择最好的一个,并给其他所有追求者发好人卡。

最后直到某个时刻所有人都不再单身,那么下一轮将不会有任何新的表白,每个人的对象也都将固定下来,整个过程自动结束——此时的搭配就一定是稳定的了。

四. 代码

4.1伪代码

4.2 java实现

import java.util.*;

class GaleShapley {
    public static class Person {
        String name;
        List<String> preferences;
        Person engagedTo;
        boolean isMan;

        Person(String name, List<String> preferences, boolean isMan) {
            this.name = name;
            this.preferences = new ArrayList<>(preferences);
            this.isMan = isMan;
            this.engagedTo = null;
        }
    }

    public static void stableMatching(List<Person> men, List<Person> women) {
        Map<String, Person> womanEngagedTo = new HashMap<>();
        Queue<Person> freeMen = new LinkedList<>();
        for (Person man : men) {
            freeMen.add(man);
        }
        while (!freeMen.isEmpty()) {
            Person man = freeMen.poll();
            int currentPreferenceIndex = 0;
            // Continue proposing to the next woman in the man's preference list
            while (currentPreferenceIndex < man.preferences.size()) {
                String womanName = man.preferences.get(currentPreferenceIndex);
                Person woman = women.stream()
                        .filter(w -> w.name.equals(womanName))
                        .findFirst()
                        .orElse(null);
                if (womanEngagedTo.containsKey(womanName) && womanEngagedTo.get(womanName).engagedTo != null) {
                    Person currentEngagedMan = womanEngagedTo.get(womanName).engagedTo;

                    // Compare preferences
                    int womanPrefIndexForCurrentEngagedMan = woman.preferences.indexOf(currentEngagedMan.name);
                    int womanPrefIndexForProposingMan = woman.preferences.indexOf(man.name);

                    if (womanPrefIndexForProposingMan < womanPrefIndexForCurrentEngagedMan) {
                        // Current engagement is broken
                        currentEngagedMan.engagedTo = null;
                        freeMen.add(currentEngagedMan);
                        womanEngagedTo.put(womanName, woman);
                        woman.engagedTo = man;
                        man.engagedTo = woman;
                        break;
                    } else {
                        // Proposal is rejected, try next woman
                        currentPreferenceIndex++;
                    }
                } else {
                    // Woman is not engaged, so man proposes
                    womanEngagedTo.put(womanName, woman);
                    woman.engagedTo = man;
                    man.engagedTo = woman;
                    break;
                }
            }
            // If man has no more preferences, he is no longer free to propose
            if (currentPreferenceIndex == man.preferences.size()) {
                freeMen.add(man);
            }
        }
    }

    public static void printMatching(List<Person> men, List<Person> women) {
        for (Person man : men) {
            if (man.engagedTo != null) {
                System.out.println(man.name + " is engaged to " + man.engagedTo.name);
            }
        }
        for (Person woman : women) {
            if (woman.engagedTo != null) {
                System.out.println(woman.name + " is engaged to " + woman.engagedTo.name);
            }
        }
    }

    public static void main(String[] args) {
        List<Person> men = new ArrayList<>();
        List<Person> women = new ArrayList<>();
        // Men's preferences
        men.add(new Person("m1", Arrays.asList("w1", "w2", "w3"), true));
        men.add(new Person("m2", Arrays.asList("w2", "w1", "w3"), true));
        men.add(new Person("m3", Arrays.asList("w1", "w3", "w2"), true));
        // Women's preferences
        women.add(new Person("w1", Arrays.asList("m2", "m1", "m3"), false));
        women.add(new Person("w2", Arrays.asList("m1", "m2", "m3"), false));
        women.add(new Person("w3", Arrays.asList("m3", "m1", "m2"), false));
        // GS and print
        stableMatching(men, women);
        printMatching(men, women);
    }
}

五. 体会

现实生活中的匹配不会和GS算法描述的流程保持一致,但即使如此,这种策略所反映的结果却和生活经验高度吻合。如果说还能有什么启示,个人觉得不应该在遇到更心仪的人的时候,就果断放弃现在陪你的人。当然单纯从算法层面来讲,GS算法通过不断迭代找到了一个最优稳定匹配,时间复杂度为O(n^2),是实现稳定匹配的一个经典算法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2263617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JWT令牌与微服务

1. 什么是JWT JWT&#xff08;JSON Web Token&#xff09;是一种开放标准(RFC 7519)&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于作为JSON对象在各方之间安全地传输信息。JWT通常用于身份验证和信息交换。 以下是JWT的一些关键特性&#xff1a; 紧凑&#xff…

视频点播系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…

docker部署Melody开源音乐管理工具

Melody是一款非常实用的开源音乐管理工具。它不仅功能强大、操作简便&#xff0c;还支持多平台检索和一键下载/上传功能。更重要的是&#xff0c;它还支持一键“解锁”无法播放的歌曲和多端适配。如果你也是音乐爱好者&#xff0c;不妨试试Melody&#xff0c;让你的音乐生活更加…

问题小记-达梦数据库报错“字符串转换出错”处理

最近遇到一个达梦数据库报错“-6111: 字符串转换出错”的问题&#xff0c;这个问题主要是涉及到一条sql语句的执行&#xff0c;在此分享下这个报错的处理过程。 问题表现为&#xff1a;一样的表结构和数据&#xff0c;执行相同的SQL&#xff0c;在Oracle数据库中执行正常&…

day4:tomcat—maven-jdk

一&#xff0c;java项目部署过程 编译&#xff1a;使用javac命令将.java源文件编译成.class宇节码文件打包&#xff1a;使用工具如maven或Gradle将项目的依赖、资源和编译后的字节码打包成一个分发格式&#xff0c;如.jar文件&#xff0c;或者.war文件(用于web应用&#xff09…

【D3.js in Action 3 精译_046】DIY 实战:在 Observable 平台利用饼图布局函数实现 D3 多个环形图的绘制

当前内容所在位置&#xff1a; 第五章 饼图布局与堆叠布局 ✔️ 5.1 饼图和环形图的创建 ✔️ 5.1.1 准备阶段&#xff08;一&#xff09;5.1.2 饼图布局生成器&#xff08;二&#xff09;5.1.3 圆弧的绘制&#xff08;三&#xff09;5.1.4 数据标签的添加&#xff08;四&#…

Swin transformer 论文阅读记录 代码分析

该篇文章&#xff0c;是我解析 Swin transformer 论文原理&#xff08;结合pytorch版本代码&#xff09;所记&#xff0c;图片来源于源paper或其他相应博客。 代码也非原始代码&#xff0c;而是从代码里摘出来的片段&#xff0c;配上简单数据&#xff0c;以便理解。 当然&…

Vscode搭建C语言多文件开发环境

一、文章内容简介 本文介绍了 “Vscode搭建C语言多文件开发环境”需要用到的软件&#xff0c;以及vscode必备插件&#xff0c;最后多文件编译时tasks.json文件和launch.json文件的配置。即目录顺序。由于内容较多&#xff0c;建议大家在阅读时使用电脑阅读&#xff0c;按照目录…

麒麟操作系统服务架构保姆级教程(二)sersync、lsync备份和NFS持久化存储

如果你想拥有你从未拥有过的东西&#xff0c;那么你必须去做你从未做过的事情 上篇文章我们说到rsync虽好&#xff0c;但是缺乏实时性&#xff0c;在实际应用中&#xff0c;咱们可以将rsync写进脚本&#xff0c;然后写进定时任务去备份&#xff0c;如果每天凌晨1&#xff1a;00…

关于小程序内嵌h5打开新的小程序

关于小程序内嵌h5打开新的小程序 三种方式 https://juejin.cn/post/7055551463489011749 只依赖于h5本身的就是 https://huaweicloud.csdn.net/64f97ebb6b896f66024ca16c.html https://juejin.cn/post/7055551463489011749 navigateToMiniProgram 故小程序webview里的h5无法…

QP:Query切词

Query 分词&#xff08;切词&#xff09; 分词指将一段连续的文本切成一个个独立且有意义的词汇&#xff0c;在文本召回中会对 Doc 文本内容分词以构建索引&#xff0c;并通过对查询词 Query 分词后去做检索。Query 分词在搜索中是一个基础信号&#xff0c;除了文本召回&#…

鸿蒙元服务从0到上架【第二篇】

第一招&#xff1a;在AppGallery后台下载对应的证书等文件 AppGallery后台 新增发布证书&#xff0c;具体操作可查看申请发布证书 申请发布Profile证书 第二招&#xff1a;在IDE中填写 第三招&#xff1a;打包【⚠️发布上架的只能是Build App】 终端展示这一片绿&#xf…

9_HTML5 SVG (5) --[HTML5 API 学习之旅]

SVG 模糊效果 HTML5中的SVG&#xff08;可缩放矢量图形&#xff09;允许我们创建高质量的二维图形&#xff0c;包括应用各种滤镜效果。模糊效果是通过<feGaussianBlur>滤镜原语来实现的。下面我将给出4个使用SVG进行模糊效果处理的示例&#xff0c;并为每个代码段添加详…

vue+node+mysql8.0,详细步骤及报错解决方案

1.下载需要安装的插件 下载express npm install express下载cors&#xff0c;用于处理接口跨域问题 npm install cors下载mysql npm install mysql 2.配置服务器 可以在vue项目的src同级创建server文件夹&#xff08;这里的位置可随意选择&#xff09; 然后依次创建&#…

相机雷达外参标定综述“Automatic targetless LiDAR–camera calibration: a survey“

相机雷达外参标定综述--Automatic targetless LiDAR–camera calibration: a survey 前言1 Introduction2 Background3 Automatic targetless LiDAR–camera calibration3.1 Information theory based method(信息论方法)3.1.1 Pairs of point cloud and image attributes(属性…

Epic游戏使用mod

以土豆兄弟为例&#xff1a; 第一步&#xff1a;获取 SteamCMD 下载官方 Steam 控制台客户端 (steamCMD) 1. 下载好后打开&#xff0c;是一个在 cmd 窗口的运行的命令行 2. 输入以下代码登录 login anonymous 第二步&#xff1a; 确认自己要下载的游戏 ID 和 mod ID 然后…

EGO Swarm翻译

目录 摘要 Ⅰ 介绍 Ⅱ 相关工作 A . 单四旋翼局部规划 B . 拓扑规划 C. 分布式无人机集群 Ⅲ 基于梯度的局部规划隐式拓扑轨迹生成 A.无需ESDF梯度的局部路径规划 B.隐式拓扑轨迹生成 Ⅳ 无人机集群导航 A 机间避碰 B. 定位漂移补偿 C. 从深度图像中去除agent Ⅴ …

FFmpeg 框架简介和文件解复用

文章目录 ffmpeg框架简介libavformat库libavcodec库libavdevice库 复用&#xff08;muxers&#xff09;和解复用&#xff08;demuxers&#xff09;容器格式FLVScript Tag Data结构&#xff08;脚本类型、帧类型&#xff09;Audio Tag Data结构&#xff08;音频Tag&#xff09;V…

基于LSTM长短期记忆神经网络的多分类预测【MATLAB】

在深度学习中&#xff0c;长短期记忆网络&#xff08;LSTM, Long Short-Term Memory&#xff09;是一种强大的循环神经网络&#xff08;RNN&#xff09;变体&#xff0c;专门为解决序列数据中的长距离依赖问题而设计。LSTM因其强大的记忆能力&#xff0c;广泛应用于自然语言处理…

在Excel中如果制作可以自动填充的序号,删除或者合并单元也可用

大家好&#xff0c;我是小鱼。在日常的办公中有时需要制作带序号的表格&#xff0c;这样可以通过序号来直观地看到有多少条信息&#xff0c;但是如果普通的批量添加序号的话&#xff0c;一旦我们删除或者合并某几行数据&#xff0c;前面的序号不会自动更新&#xff0c;序号显示…