问题:n个男生与n个女生进行配对,每个人恰好一个舞伴。若不存在:男u和女v没有配对,而他们喜欢对方的程度大于各自当前的舞伴程度。
Gale-Shapley算法步骤:
1、每个尚未匹配的男生在他还没有邀请的女生中选一个自己最喜欢的。
2、若被邀请的女生没有舞伴,则接受邀请;若已经有了舞伴,比较当前舞伴与该男生排名,若当前舞伴排名较低,则抛弃之,接受当前邀请,反之拒绝邀请。
3、若该轮男生没有找到舞伴,则再次加入到未匹配队伍中。
算法正确性证明:
对以上算法进行分析,我们会发现两个现象:1、女人从接到第一个求婚起就开始一直保持约会的状态,并且她约会的对象会越来越好(从她的排序表来看);2、男人求婚的对象(女人)会越来越差!
下面,我们对这个算法的正确性证明如下:
1、算法的有限性——算法最多会在执行完n2次while循环的时候结束:每次while循环,一个男人向一个女人求婚,因为一共有n个男人和n个女人,所以最多只有n2次求婚。
2、算法的完美性——所有的男女都进行了配对:(反证法)假设男人M在算法结束后没有配对,那么相应的肯定会存在一个女人假设为W也没有配对,那么可以肯 定女人W从来都没有收到求婚的请求,但是根据现象2,男人M会向所有的女人求婚一直到有人接受,那么矛盾就出现了,于是假设不成立,命题得证。
3、算法的稳定性——不存在不稳定对:(反证法)假设在GS配对里,Amy-Yancey、Bertha-Zeus分别是2对,假设A—Z是不稳定对,那 么出现这种现象有两种可能:a、Z从来没有向A求婚,根据现象2,得出Z会更喜欢他的GS对象,而不是A,那么A—Z就是稳定的;b、Z向A求过婚,但是 被A拒绝了(可能是当场拒绝,也可能是后来A遇到更好的抛弃了Z),那么也可以得出A更喜欢她的GS对象,而不是Z,所以A—Z也是稳定的。所以在任何情 况下,A—Z都是稳定的,假设不成立,命题得证。
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
#define N 1005
int pref[N][N],order[N][N],next[N];
int future_husband[N],future_wife[N];
queue<int>q;
//订婚
void engage(int man,int woman){
int m=future_husband[woman];
if(m){ //女士有现任未婚夫m
future_wife[m]=0;//抛弃m
q.push(m); //m加入未婚男士队列
}
future_wife[man]=woman;
future_husband[woman]=man;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j)
scanf("%d",&pref[i][j]);
next[i]=1; //接下来应该向排名为1的女士求婚
future_wife[i]=0;//无未婚妻
q.push(i); //未婚男士队列
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
int x;
scanf("%d",&x);
order[i][x]=j; //在编号为i的女士心目中,编号为x的男士的排名
}
future_husband[i]=0; //无未婚夫
}
while(!q.empty()){
int man=q.front();q.pop();
int woman=pref[man][next[man]++]; //指向当前求婚对象,并使next后移一个
if(!future_husband[woman])//女士没有未婚夫
engage(man,woman);
else if(order[woman][man]<order[woman][future_husband[woman]])//代替女士的现任未婚夫
engage(man,woman); //排名比现任未婚夫靠前,代替女士的现任未婚夫
else q.push(man); //被拒
}
while(!q.empty()) q.pop();
for(int i=1;i<=n;++i) printf("%d\n",future_wife[i]);
if(t) puts("");
}
return 0;
}