婚姻匹配问题(Gale-Shapley算法)

1.问题描述

有N男N女,每个人都按照他对异性的喜欢程度排名。现在需要写出一个算法安排这N个男的、N个女的结婚,要求两个人的婚姻应该是稳定的。何为稳定?有两对夫妻M1 F2,M2 F1。M1心目中更喜欢F1,但是他和F2结婚了,M2心目中更喜欢F2,但是命运却让他和F1结婚了,显然这样的婚姻是不稳定的,随时都可能发生M1和F1私奔或者M2和F2私奔的情况。所以在做出匹配选择的时候(也就是结婚的时候),我们需要做出稳定的选择,以防这种情况的发生。

要求:boys和girls各自给出自己心仪的嘉宾的顺序,请编写程序求出一种稳定的匹配,使匹配结果不会发生私奔现象。

2.设计思路

        首先我们在思考的时候从第一次双方的配对情况思考,由男方向女方求婚,有多少个男性就发出多少次邀请,在发起邀请时要考虑优先级,所以男性按照女性配偶在自己心中的优先级发出邀请,如果对方已有婚约则女方会对两位男性在自己心中的地位进行比较,再选择其中优先级高的男性,以此类推直至所有人都认为自己现在的婚约是最好的。

        经过上述分析我们可知,我们需要两个类男性,女性,并且在这两个类中我们需要多个参数去表明两者的状态以下是我们需要的参数:1.判断是否处于婚姻状态的boolean类型的数据,2.存储结构为队列的男性对女性偏好,3.存储结构为数组的女性对男性偏好4.表明当前男性或女性的名字的int类型的数据,5.表明当前对象的婚约对象的数据.

3.代码实现

Man类存储男性数据

import java.util.PriorityQueue;
import java.util.Queue;

public class Man implements Comparable<Man>{
    private  int name;
    public int[] favorNum;//男性的偏好数组
    private Queue<Woman> favor;//男性的偏好队列
    private boolean status;//判断男性是否已有婚约对象
    public  boolean failed;
    private Woman currentGirl;//表示当前的婚约对象
    public Man(int name,int numWoman){//初始化数据
        this.name=name;
        favorNum=new int[numWoman];//
        favor = new PriorityQueue<>();
        status=false;
        currentGirl=null;//初始没有婚约对象
        failed=false;
    }
    public void EntryQueue(Woman[] womanGroup){
        for(int favorGirl:favorNum){
            favor.add(womanGroup[favorGirl]);
        }
    }
    public int Invitation(){
        if(status) return 0;//如果已有婚约对象则直接返回
        if(failed) return 0;
        else{
            Woman Girl = favor.poll();
            boolean result = Girl.ReceiveInvitation(this);
            if(result){
                status = true;
                currentGirl = Girl;
                return 1;
            }
            if(favor.isEmpty()){
                failed=true;
            }
        }
        return 1;
    }
    public void ChangeState(){//用于女方取消当前婚约
        status = false;
        currentGirl=null;
    }
    public int name(){
        return name;
    }
    public int GirlName(){
        if(currentGirl!=null){
            return currentGirl.name();
        }
        else{
            return ' ';
        }
    }
    @Override
    public int compareTo(Man man) {//自定义比较方法
        if(name==man.name) return 0;
        else return -1;
    }

}

Woman类存储女性对象

public class Woman implements Comparable<Woman> {
    private int name;
    private  Man[] favor;//每位女性的偏好数组
    private boolean status;//表示当前的婚约状况
    private Man currentMan;//表示当前的婚约对象
    public Woman(int name,Man[] favor){//初始化属性
        this.name=name;
        this.favor=favor;
        status=false;
        currentMan=null;
    }
    public boolean ReceiveInvitation(Man man){//括号内的Man对象指代发出邀请的男性
        if(!status){//如果向其发送婚约邀请的对象没有婚姻则暂时将其定为婚约对象
            for(Man favorMan:favor){
                if(favorMan==man){//如果存在该男性
                    currentMan=man;
                    status=true;
                    System.out.println("man:"+man.name()+"和woman:"+name+"暂时配对\n");
                    return  true;
                }
            }
            System.out.println("man:"+man.name()+"和woman:"+name+"配对失败");
            return false;
        }
        else{//如果已有婚约者则对两者进行比较择优选之
            for(Man favorMan:favor){
                if(favorMan==currentMan){
                    System.out.println("配对失败,woman:"+name+"仍与man:"+man.name()+"配对\n");
                    return false;
                }
                else if(favorMan==man){
                    currentMan.ChangeState();
                    System.out.println("man:"+man.name()+"取代man:"+currentMan.name()+"与woman:"+name+"暂时配对\n");
                    currentMan =man;
                    return true;
                }
            }
            System.out.println("man:"+man.name()+"与woman:"+name+"配对失败,woman:"+name+"仍与man:"+currentMan.name()+"配对\n");
            return false;
        }
    }
    public int name(){
        return name;
    }
    @Override
    public int compareTo(Woman woman) {
        if(name== woman.name()) return 0;
        else return -1;
    }
}

实现匹配算法的Gale-Shapley算法

import java.util.Scanner;
public class GaleShapley {
    public  Man[] ManGroup;
    public Woman[] WomanGroup;
    public static Scanner sc ;
    public GaleShapley(Scanner sc,int n){
        CreatManGroup(sc,n);
        CreatWomanGroup(sc,n);
        InsertManFavor();
    }
    public void CreatManGroup(Scanner sc,int n){
        ManGroup = new Man[n];
        for(int i=0;i<n;i++){
            int manName=i+1;
            //创建Man对象
            Man man =new Man( manName,n);
            System.out.println("男性"+manName+"的偏好为:");
            int Num=sc.nextInt();
            String s = String.valueOf(Num);
            for(int j=0;j<n;j++){
                    man.favorNum[j]=s.charAt(j)-'1';
            }
            ManGroup[i]=man;//存储男性对象
        }

    }
    public  void CreatWomanGroup(Scanner sc,int n){
        WomanGroup=new Woman[n];
        for(int i=0;i<n;i++){
            int womanName=i+1;
            Man[] men = new Man[n];
            System.out.println("女性"+womanName+"的偏好为:");
            int favorNum=sc.nextInt();
            String sNum = String.valueOf(favorNum);
            for(int j=0;j<n;j++){
                favorNum=sNum.charAt(j)-'1';
                if(favorNum<0) continue;
                Man favorMan=ManGroup[favorNum];
                men[j] =favorMan;
            }
            WomanGroup[i]=new Woman(womanName,men);
        }
    }
    public void InsertManFavor(){
        for(Man man: ManGroup){
            man.EntryQueue(WomanGroup);
        }
    }
    public static void main(String[] args) {
        sc = new Scanner(System.in);
        System.out.println("请输入男性和女性的数量");
        int n=sc.nextInt();
        GaleShapley gs = new GaleShapley(sc,n);
        int num=1;
        int flag=1;
        while(num!=0){
            System.out.printf("--------------------"+"\n开始第"+flag+"轮邀请"+"\n--------------------\n");
            num=0;
            flag++;
            for(Man man:gs.ManGroup){
                num+=man.Invitation();
            }
        }
        System.out.println("\n最终结果\n");
        for(Man man:gs.ManGroup){
            System.out.printf("man:"+man.name()+" --> woman:"+man.GirlName());
            System.out.println("  ");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值