GS稳定匹配算法是为了解决“稳定匹配难题(Stable Matching Problem)”而提出的,所谓稳定匹配难题

     听班助在课上给我们讲的一个算法,挺有趣的,一开始不是很理解,在网上看了一些资料后,就差不多了,做个笔记,记录下来吧,这也是我第一次写算法的博客笔记。

 

GS算法简介:

稳定匹配难题,是指: 有n个男人,还有n个女人,男人心目中有自己的心上人列表,从最喜欢的女神一直排列下去,而女人心中也有相同的列表。很明显的,某男喜欢的女人,她可能根本看不上他。而多个女人喜欢的男人,也不可能同时娶这些女人。所以要找出一个让所有人都能结婚,且大家都满意的方案是很难的。

    1962 年,美国数学家 David Gale 和 Lloyd Shapley 发明了一种寻找稳定婚姻的策略。不管男女各有多少人,不管他们各自的偏好如何,应用这种策略后总能得到一个稳定的婚姻搭配。这一个算法在2012年获得了诺贝尔经济学奖。(参考http://zhidao.baidu.com/question/494779153.html)

算法的步骤是:

第一步,是由男人们一轮一轮的去找他最喜欢的女人表白,女人可以选择接受,也可以选择拒绝。 此时女人会遇到三种情况,第一是没人来表白;第二是有一个人来表白;第三是有多个人来表白。女人的策略是,如果没人来表白就再等一轮,如果有一个人来表白就暂时同他交往着,如果有多个人来表白,就同最喜欢的那个交往。一轮过后,有些男人有女友了,有些还打着光棍。

 

第二步,那些光棍们重复上一轮的行为,从还没被拒绝的女生中,找自己最心仪的女人表白。女人会遇到一个特殊情况,自己有男友了,但是又有一个男人来表白。如果新来的男人比现在的差,她就忽略,如果比现在的好,那就劈腿换新人。

 

第三步再重复第二步的行为。如此循环往复,一直到最后每个人都成功匹配为止。Shapley和Gale两人从数学上证明了,这种策略的结果是最稳固的。

证明:

稳定匹配要证明两个问题,一个稳定的匹配也必须满足下面的条件:

①匹配是完美的。即每个男人都会找到自己最终的女神,每个女人都会找到自己的男人,不存在有人是单身。

②不包含不稳定因素。

(不稳定因素:有两对夫妻(M1 F2),(M2 F1)。M1心目中更喜欢F1,但是他和F2结婚了,M2心目中更喜欢F2,但是命运却让他和F1结婚了,显然这样的婚姻是不稳定的,随时都可能发生M1和F1私奔或者M2和F2私奔的情况。所以在做出匹配选择的时候(也就是结婚的时候),我们需要做出稳定的选择,以防这种情况的发生。)

证明问题①(用反证法):随着轮数的增加,总有一个时候所有人都能配上对。因为男生根据自己心目中的排名依次对女士进行表白,假如有一个人没有配上对,那么这个人必定是向所有的女孩进行表白了。但是女孩只要被表白过一次,女孩就不可能是单身,也就是说此时所有的女生都不是单身的,这与有一个人没有配上对是相悖的,男孩女孩人数相等。所以假设不成立。该算法一定会使得所有人都能够配对成功,即为完美匹配。

证明问题②(也是反证法):随着轮数的增加,男士追求的对象越来越糟,而女士的男友则可能变得越来越好。假设男A和女1各有各自的对象,但是比起现在的对象,男A更喜欢女1,所以,在此之前男A肯定已经跟女1表白过的,并且女1拒绝了男A,也就是女1有了比男A更好的男友,不会出现私奔的情况,这样就不会包含稳定因素。

由①②证明了这个的算法的正确性(参考)

  1:  while  存在男人m是自由的且还没对每个女人都求过婚  
   2:        选择这个男人m  
   3:                  令w是m的优先表中还没求过婚的最高排名的女人  
   4:          if  w是自由的    
   5:              (m,w)变成约会状态  
   6:          else  w当前与m1约会  
   7:                if  w更偏爱m1而不爱m  
   8:                      m保持自由  
   9:                else    w更偏爱m而不爱m1  
  10:                     (m,w)变成约会状态  
  11:                      m1变成自由  
  12:                endif  
  13:                    endif endwhile 


借鉴大神的代码

gs算法python GS算法的结果唯一吗_GS稳定匹配算法算法

gs算法python GS算法的结果唯一吗_GS稳定匹配算法算法_02

#include<iostream>
#include <stack>

using namespace std;

#define NUM 4
#define NIL -1

int GetPositionFromLaday(int ladayArray[][NUM], int laday, int man)
{
    for(int i=0; i<NUM; i++)
        if(ladayArray[laday][i] == man)
            return i;
    return NIL;
}

void ChoosePartener(stack<int>& manStack, int manPos, int manArray[][NUM], int ladayArray[][NUM], int manPerfer[], int manStartPos[], int ladayNow[])
{
    //选择自己名单上排在首位的女人
        int perferLaday = manArray[manPos][manStartPos[manPos]];
        //如果该女孩没有接受过表白,则接受该男孩的表白
        if(ladayNow[perferLaday] == NIL)
        {
            ladayNow[perferLaday] = manPos;
            manPerfer[manPos] = perferLaday;
        }
        //如果已经有人向她表白,则判断其现在拥有的有没有现在追求的好
        else
        {
            int oldPos = GetPositionFromLaday(ladayArray, perferLaday, ladayNow[perferLaday]);
            int newPos = GetPositionFromLaday(ladayArray, perferLaday, manPos); 
            if(oldPos < newPos)
            {
                manStartPos[manPos]++;//说明该女生更喜欢现在拥有的,选心目中第二位
                //加入单身行列
                manStack.push(manPos);
            }
            else //换男友
            {
                //被甩的男友恢复自由身份
                manStartPos[ladayNow[perferLaday]]++;
                //加入单身行列
                manStack.push(ladayNow[perferLaday]);
                //将追求的男士改为现任男友
                ladayNow[perferLaday] = manPos;
                manPerfer[manPos] = perferLaday;
            }
        }
}

int main()
{
    int manArray[NUM][NUM] ={{2,3,1,0},{2,1,3,0},{0,2,3,1},{1,3,2,0}};    
    int ladayArray[NUM][NUM] = {{0,3,2,1},{0,1,2,3},{0,2,3,1},{1,0,3,2}};

    int manPerfer[NUM] = {0};//每位男生选中的女生
    int manStartPos[NUM] = {0};//记录每位男生选取的是心目中第几位的女生
    int ladayNow[NUM] = {NIL,NIL,NIL,NIL};//女生对应的男生

    stack<int> manStack; // 还处于单身的男士

    //进行第一轮迭代,每个男生都选择自己名单上排在首位的女生。
    for(int pos=0; pos<NUM; pos++)
    {
        ChoosePartener(manStack, pos, manArray, ladayArray, manPerfer, manStartPos,ladayNow);
    }

    while(manStack.size()!=0)
    {
        int manPos = manStack.top();
        manStack.pop();
        ChoosePartener(manStack, manPos, manArray, ladayArray, manPerfer, manStartPos,ladayNow);
    }

    for(int i =0;i<NUM; ++i)
        cout<<"Man NO.: "<<i<<" Laday NO.: "<<manPerfer[i]<<endl;
}

View Code