稳定匹配算法证明

6 篇文章 1 订阅

稳定匹配

题目



稳定匹配问题

阅读《算法设计》1.1 p1-9 完成论文,要求:

  1. 用集合论的语言描述稳定匹配问题算法的输入、输出;

  2. 描述完美匹配、稳定匹配,并以例示之;

  3. 描述算法思想,并用C、Java或Python语言实现之;

  4. 证明命题、定理1-8,用自己的语言正确、清晰描述。



1. 问题的形式化描述

1.1 定义

假设n个男人的集合 M = { m 1 , m 2 , . . . , m n } M = \{ m_1, m_2, ...,m_n\} M={m1,m2,...,mn} 与n个女人的集合 W = { w 1 , w 2 , . . . , w n } W =\{ w_1, w_2, ..., w_n\} W={w1,w2,...,wn} . 令 M × W M \times W M×W(笛卡尔积)表示所有可能的形如 ( m , w ) (m, w) (m,w)的有序对的集合, 其中 m ∈ M , w ∈ W m \in M , w \in W mM,wW。 一个匹配S是来自 M × W M \times W M×W 的有序对的集合。

匹配 S S S:是来自 M × W M \times W M×W的有序对的集合 ( M × W 的 子 集 ) (M \times W的子集) (M×W), 每个 M M M的成员和每个 W W W的成员至多出现在 S S S的一个有序对中

完美匹配 S ′ S' S:每个 M M M的成员和每个 W W W的成员恰好出现在 S ’ S’ S的一个对中。例如:有n家公司和n位应聘者, 其中每家公司都能招一位应聘者, 每位应聘者都能进入一家公司,这样每家公司和每位应聘者都恰好形成一个有序对。

稳定匹配 S S S: 首先S是完美匹配 , 其次 S S S中不含有不稳定因素。 例如:有n家公司和n位应聘者, 其中每家公司都能招一位应聘者, 每位应聘者都能进入一家公司,这样每家公司和每位应聘者都恰好形成一个有序对;并且每家公司都招到一位满意的应聘者, 每位应聘者都能进入一家满意的公司。

最佳有效伴侣 : 如果所有的男人都偏爱不同的女人,这是真的。首先,如果存在一个稳定匹配包含了 ( m , w ) (m,w) (m,w)对, 我们就说女人 w w w是男人 m m m的有效伴侣, 如果 w w w m m m的有效伴侣,且没有别的在 m m m的排名中比 w w w更高的女人是他的有效伴侣, 那么 w w w就是 m m m的最佳有效伴侣。 用集合 S ∗ S^* S表示最佳有效伴侣集合; S ∗ = { ( m . b e s t ( m ) ) : m ∈ M } S^* = \{(m.best(m)) : m\in M\} S={(m.best(m)):mM}

1.2 问题描述

n n n个单身男性集合 M = { m 1 , m 2 , … , m n } M = \{m_1, m_2, …, m_n\} M={m1,m2,,mn} n n n个单身女性集合 W = { w 1 , w 2 , … , w n } W = \{w_1, w_2, …, w_n\} W={w1,w2,,wn}

假设每个男性对不同女性的喜好程度都不同,单身女性也是如此。

男性 m i ( 1 ≤ i ≤ n ) m_i(1 \leq i \leq n) mi(1in)有一张属于自己的对 n n n个女性的优先表, m i m_i mi把他最偏爱的女性放在第一位,第二偏爱的女性放在第二位,以此类推,排名越靠前的女性表示 m i m_i mi越爱慕该女性。同理,女性 w i ( 1 ≤ i ≤ n ) w_i(1 \leq i \leq n) wi(1in)也有一张属于自己的对 n n n个男性的优先表,排名越靠前的男性越受该女性的喜爱。最后每个人都要有伴侣。对每组优先表是否存在一个稳定匹配? 给定一组优先表, 如果存在稳定匹配, 能否有效得将其构造出来?

2. 算法思想

​ 首先所有男生和女生都是自由的,每个男生对所有女生进行排名,即最偏爱的女生排在最前、最不爱的女生放在最后。同样,每个女生也需要给男生排名。接着,男生将按照自己的优先表一轮一轮地向偏爱的女生求婚,女生也将按照自己的优先表接受或拒绝对方的追求。
​   第一轮,每个男生都向自己名单上排在第一位的女生求婚。此时,一个女生可能面对的情况有三种:没有人跟她求婚、只有一人跟她求婚、有不止一人跟她求婚。第一种情况下,这个女生什么都不做,继续等待即可;第二种情况下,女生接受那个人的表白,进行约会状态;在第三种情况下,女生从所有追求者中选择自己最喜欢的那一位,进行约会状态,并拒绝其他所有的追求者。
  第一轮结束后,有些男生已经有对象了而有些男生仍然是自由身。在第二轮求婚中,每个单身男生都会从所有还没拒绝过自己的女生中选出自己最喜欢的那一个,并向她求婚,不管她现在是否是单身。和第一轮一样,每个被求婚的女生需要从追求者中选择最喜欢的男生,并拒绝其他追求者。如果这个女生当前已经有男朋友了,当她遇到了优先表上更好的追求者时,她将会和现男友分手,投向新追求者的怀抱。这样以来,一些男生将脱单,而一些不幸的男生也会被分手,重新加入自由身的行列。
  之后的每一轮中,拥有自由的男生将继续追求优先表中的下一个女生;女生则从包括现男友在内的所有追求者中选择最好的一个。这样每一轮地进行下去,直到某个时刻所有人都不是自由的,那么算法将结束,此时所有约会将成为最后的结果,每个人的对象也都将固定下来,这时的搭配就一定是稳定的。

稳定匹配问题算法的输入: ∃ m ∈ M \exists m\in M mM 是自由的且没和每个 w ∈ W w\in W wW都求过婚

稳定匹配问题算法的输出 : ∀ w ∈ W \forall w\in W wW 至多存在一个求婚 m ∈ M m\in M mM且每个 w w w都会与求婚 m m m结婚.


3. 算法实现与示例

用Java实现算法

package GS;
import java.util.Arrays;
import java.util.Scanner;


class People {
    private int favor = 0;   //记录追求过女生的次数
    private int[] rank;     //存放优先表中的元素
    private boolean sign = false; //表示自由, 没有对象
    private int now; //表示与那个人约会
    
    public int getFavor () {
        return favor ;
    }
    
    public void setFavor (int favor ) {
        this.favor = favor ;
    }
    
    public int[] getRank() {
        return rank;
    }
    
    public void setRank(int[] rank) {
        this.rank = rank;
    }
    
    public boolean isSign() {
        return sign;
    }
    
    public void setSign(boolean sign) {
        this.sign = sign;
    }
    
    public int getNow() {
      return now;
    }
    
    public void setNow(int now) {
        this.now = now;
    }

}

public class Gs {
	
	public static void main(String[] args) {
        System.out.println("请输入匹配的男生数:");
		Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
        People women[] = new People[num];
        People men[]= new People[num];

        for(int i=0;i<num;i++){
        	System.out.println("输入第 "+(i+1)+"个男生偏爱的优先表(以空格隔开): ");
            int[] a=new int[num];
            for(int j=0;j<num;j++){
                a[j]=sc.nextInt();
            }
            men[i]=new People();   //初始化
            men[i].setRank(a);
            System.out.println(Arrays.toString(men[i].getRank()));//输出该男生的优先表
        }//建立男生的优先表

        for(int i=0;i<num;i++){
        	System.out.println("输入第 "+(i+1)+"个女生偏爱的优先表(以空格隔开): ");
            int[] a=new int[num];
            for(int j=0;j<num;j++){
                a[j]=sc.nextInt();
            }
            women[i]=new People();   //初始化
            women[i].setRank(a);
            System.out.println(Arrays.toString(women[i].getRank()));//输出该女生的优先表
        }//建立女生的优先表
        
        int i = 0;
        while(i<num){
            if(!men[i].isSign()){  //该男生的编号为(i+1)号,且是自由身则进入判断
                int chase =men[i].getRank()[men[i].getFavor()]; //目前最偏爱chase号女生
                System.out.println((i+1)+"号男生目前最偏爱的"+chase+"号女生");
                men[i].setFavor(men[i].getFavor()+1); //向女生求过婚了,记录求婚的次数
                System.out.println("追求过的次数为:"+men[i].getFavor());
               	if(!women[chase-1].isSign()){ //如果偏爱的女生没有约会
                   men[i].setSign(true);
                   men[i].setNow(chase);
                   women[chase-1].setSign(true);
                   women[chase-1].setNow(i+1);
                   System.out.println((i+1)+"号男生和"+chase+"号女生约会");
               }else{   //对比现在这个男生和正在约会的男生哪个排名更前
                   System.out.println("女生有约会对象");
                   int later=0,former=0;
                   for(int r=0;r<num;r++){ //对比第chase号女生的优先表,获取男生排名
                       if(women[chase-1].getRank()[r]==(i+1)){//二维数组
                           later=r;//获取(i+1)号男生的排名
                       }
                       if(women[chase-1].getRank()[r]==women[chase-1].getNow()){
                           former=r;
                       }
                   }
                   if(later>former){//对比排名
                       System.out.println(chase+"号女生更偏爱当前约会的"+women[chase-1].getNow()+"号男生");
                       i=-1;//还有人是自由的,还没都脱单,还得重新再匹配
                   }else if(later<former){//当前(i+1)号男生比约会的男生排名靠前
                       System.out.println(chase+"号女生更偏爱现在求婚的"+(i+1)+"号男生");
                       System.out.println(women[chase-1].getNow()+"变自由,单身");
                       men[women[chase-1].getNow()-1].setSign(false);//获得自由,单身
                       men[women[chase-1].getNow()-1].setNow(100);
                       men[i].setSign(true);
                       men[i].setNow(chase);
                       women[chase-1].setNow(i+1);
                       i=-1;//还有人是自由的,还没都脱单,还得重新再匹配
                   }
               }
            }
            i++;
        }//循环结束,已经匹配完成
        
        System.out.print("最终稳定匹配的结果: ");
        for(int a=0;a<num;a++){
        	System.out.print(men[a].getNow()+" ");
        }//输出最终男生匹配女生的结果
        sc.close();
        System.out.println();  
    }
}

示例:

有4位男生和4位女生进行匹配

1号男生的优先表 : 2 4 3 1

2号男生的优先表 :1 3 4 2

3号男生的优先表 : 3 1 2 4

4号男生的优先表 : 4 2 1 3

1号女生的优先表 : 1 3 4 2

2号女生的优先表 : 3 4 1 2

3号女生的优先表 : 2 3 1 4

4号女生的优先表 : 4 2 3 1

输出的稳定匹配为: 2 1 3 4

输出结果:

请输入匹配的男生数:
4
输入第 1个男生偏爱的优先表(以空格隔开): 
2 4 3 1
[2, 4, 3, 1]
输入第 2个男生偏爱的优先表(以空格隔开): 
1 3 4 2
[1, 3, 4, 2]
输入第 3个男生偏爱的优先表(以空格隔开): 
3 1 2 4
[3, 1, 2, 4]
输入第 4个男生偏爱的优先表(以空格隔开): 
4 2 1 3
[4, 2, 1, 3]
输入第 1个女生偏爱的优先表(以空格隔开): 
1 3 4 2
[1, 3, 4, 2]
输入第 2个女生偏爱的优先表(以空格隔开): 
3 4 1 2
[3, 4, 1, 2]
输入第 3个女生偏爱的优先表(以空格隔开): 
2 3 1 4
[2, 3, 1, 4]
输入第 4个女生偏爱的优先表(以空格隔开): 
4 2 3 1
[4, 2, 3, 1]
1号男生目前最偏爱的2号女生
追求过的次数为:1
1号男生和2号女生约会
2号男生目前最偏爱的1号女生
追求过的次数为:1
2号男生和1号女生约会
3号男生目前最偏爱的3号女生
追求过的次数为:1
3号男生和3号女生约会
4号男生目前最偏爱的4号女生
追求过的次数为:1
4号男生和4号女生约会
最终稳定匹配的结果: 2 1 3 4 

4. 算法时间复杂度分析

while(i<num){  //频度为num+1
     if(!men[i].isSign()){ 
     int chase =men[i].getRank()[men[i].getFavor()]; 
     System.out.println((i+1)+"号男生目前最偏爱的"+chase+"号女生");
     men[i].setFavor(men[i].getFavor()+1); 
     System.out.println("追求过的次数为:"+men[i].getFavor());
     if(!women[chase-1].isSign()){ 
     men[i].setSign(true); //频度为num+1
     men[i].setNow(chase); //频度为num+1
     women[chase-1].setSign(true); //频度为num+1
     women[chase-1].setNow(i+1); //频度为num+1
     System.out.println((i+1)+"号男生和"+chase+"号女生约会");//频度为num
     }else{  
           System.out.println("女生有约会对象");
           int later=0,former=0;
           for(int r=0;r<num;r++){ //频度为nun*nun+1
           if(women[chase-1].getRank()[r]==(i+1)){ //频度为num*num+1
           later=r; //频度为num*num+1
      }
      	if(women[chase-1].getRank()[r]==women[chase-1].getNow()){
      	former=r;
        }
}

时间复杂度 T ( n ) = O ( n 2 ) T(n) = O(n^2) T(n)=O(n2)


5. 算法的性质及其证明


命题1.1 w w w从接受对她的第一次求婚开始保持约会状态,且她正在约会的一系列伴侣(依照她的优先表)变得越来越好。

证明 : 男生一开始向偏爱的女生求婚,女生暂时答应进行约会状态, 但如果遇到在她优先表中比现男友的排名还靠前的男生,就接受那些排名更高的男生。因此,女生的伴侣不会变得差,只会不变或者变的越来越好。


命题1.2 m m m求过婚的一系列女人(依照他的优先表)变得越来越差。

证明:当女生收到另外一些比当前男生排名更高的男生时, 当前男生就会变成单身。又因为男生一开始就是向最偏爱的女生求婚,如果分手,就只能追求男生的优先表排名向后的女生。因此,男生求过婚的女生要么不变,要么变得越来越差。


定理1.3 G-S​算法在至多 n 2 n^2 n2次While循环的迭代之后终止.

证明: 匹配最终结果是每个人都会结婚。只要匹配没有结束,那么每一轮匹配就一定至少存在一个男生,从他的优先表里排除一个女生;因为匹配过程中一定存在某个女生至少被两位男生追求,而且至少一位男生得把这位女生从优先表中排除,往后去追求。对于n位男生和n位女生来说,每个男生优先表中有n个女生,共有 n 2 n^2 n2个追求结果。但由于男生排除女生后,女生不会再被加入到男生的优先表中,所以每一轮匹配数量在减少,因此匹配最多 n 2 n^2 n2次while循环的迭代之后终止。


命题1.4 如果 m m m在算法执行的某点是自由的,那么存在一个他还没有向她求过婚的女人.

证明: 假设 m m m在某一个时刻是自由的且已经向所有女生都求过婚了,那么此刻所有女生都应该在约会状态上,即有n个女生和n个男生进行约会,但是男生和女生的数量是相等的,因此不存在m不在约会状态上,此假设是矛盾的。因此如果 m m m在算法执行的某点是自由的,那么存在一个他还没有向她求过婚的女人。


命题1.5 终止时返回的集合 S S S是一个完美匹配

证明: 用反证法,假设终止时返回的集合S不是一个完美匹配,这时就存在至少一个男生是自由的,而这自由的男生已经向所有女生求过婚才使得循环终止,即每个女生都有一个比这个自由男生都要偏爱的男生。由于最后一轮,每个女生都有一个对象,又因为男女数量相同,所以当所有女生有对象的同时,所有男生也应该都有对象,因此假设不成立。即终止时返回的集合 S S S是一个完美匹配。


定理1.6 考虑G-S算法的一次执行,它返回一个对的集合 S S S。集合 S S S是一个稳定匹配。

证明: 由于G-S算法终止时返回的集合是一个完美匹配,因此要证集合S是一个稳定匹配,只需证明集合S不存在不稳定的因素即可。假设不稳定因素涉及集合S中的两对 ( m 1 , w 1 ) (m_1 , w_1) (m1,w1) ( m 2 , w 2 ) (m_2,w_2) (m2,w2), 他们之间的关系是 m 1 m_1 m1偏爱 w 2 w_2 w2而不爱 w 1 w_1 w1,且 w 2 w_2 w2偏爱 m 1 m_1 m1而不爱 m 2 m_2 m2。由G-S算法可知, m 1 m_1 m1 w 1 w_1 w1的求婚是最后一次求婚。如果 m 1 m_1 m1 w 2 w_2 w2求过婚, 那么 w 2 w_2 w2 m 1 m_1 m1的优先表上比 w 1 w_1 w1靠前,即 m 1 m_1 m1更偏爱 w 2 w_2 w2, 但是 w 2 w_2 w2因为拒绝了 m 1 m_1 m1才使得 m 1 m_1 m1 w 1 w_1 w1结婚, 即 w 2 w_2 w2并不偏爱 m 1 m_1 m1, 与假设矛盾。如果 m 1 m_1 m1没有向 w 2 w_2 w2求过婚, 那么 m 1 m_1 m1的优先表上 w 1 w_1 w1的排名比 w 2 w_2 w2靠前, 即 m 1 m_1 m1更偏爱 w 1 w_1 w1, 与假设矛盾。因此返回的集合不存在不稳定因素,集合 S S S是一个稳定匹配。


定理1.7 G-S算法的每次执行都得到集合 S ∗ S^* S.

证明 : 用反证法,假设G-S算法某次执行得到匹配S, 该匹配中存在男生与一位不是最佳有效伴侣的女生匹配。根据男生的优先表排序,存在有男生被最佳有效伴侣拒绝过。设该男生为m,其最佳有效伴侣为w,有三种情况:第一种,w有与别的男生约会且该男生的排名比m靠前,因而m被拒绝。第二种,w与m约会,但因为有比m排名更靠前的男生向w求婚,w接受别的男生并拒绝m。第三种,m被w拒绝已经发生了。因为w是m的有效伴侣,则存在一个包含(m,w)稳定匹配 S ′ S' S,且设 ( m 1 , w 1 ) (m_1,w_1) (m1,w1)也属于 S ′ S' S m m m w w w拒绝是在某次执行中一位男生被一位有效伴侣第一次拒绝。另一位男生 m 1 m_1 m1与w开始约会,此时 m 1 m_1 m1还没有被任何有效伴侣拒绝过,由于他求婚按优先表的排序进行, m 1 m_1 m1偏爱w而不爱另一个女生 w 1 w_1 w1。又w更偏爱 m 1 m_1 m1,因此他们可以组成一对,即 ( m 1 , w ) (m_1,w) (m1,w) , 而该元素不属于 S ′ S' S集合,因此产生了不稳定的因素, 即与假设 S ′ S' S是稳定匹配矛盾.所以G-S算法的每次执行都得到集合 S ∗ S^* S


命题1.8 在稳定匹配 S ∗ S^* S中每个女人与她最差的有效伴侣配对.

证明 : 用反证法, 假设在 S ∗ S^* S中存在一对匹配 ( m , w ) (m,w) (m,w)使得 m m m不是 w w w的最差有效伴侣, 则存在稳定匹配 S S S, w w w的优先表上比 m m m排名靠后的男生匹配.在 S S S中, m m m与另一个女生匹配, 但该女生并不是最佳有效伴侣, 即 m m m更偏爱 w w w, 但此时的匹配有不稳定的因素, m m m会去追求 w w w,而 w w w会去接受 m m m。因此 S S S是不稳定的, 与假设矛盾。所以在稳定匹配 S ∗ S^* S中每个女人与她最差的有效伴侣配对。




附加:
   《算法设计》电子版

   提取码:6666

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值