1.GS算法基础
有N男N女,每个人都按照他对异性的喜欢程度排名。现在需要写出一个算法安排这N个男的、N个女的结婚,要求两个人的婚姻应该是稳定的。
何为稳定?
有两对夫妻M1 F2,M2 F1。M1心目中更喜欢F1,但是他和F2结婚了,M2心目中更喜欢F2,但是命运却让他和F1结婚了,显然这样的婚姻是不稳定的,随时都可能发生M1和F1私奔或者M2和F2私奔的情况。所以在做出匹配选择的时候(也就是结婚的时候),我们需要做出稳定的选择,以防这种情况的发生。
2.GS算法流程
1.初始时每个左顶点尝试与名单上排在首位的右顶点匹配,此时会有两种情况
(1)该右顶点未被匹配,则与该左顶点匹配
(2)该右顶点已被匹配过,则将当前左顶点与和其已经匹配的左顶点比较,取优先级更大的左顶点
2.每个左顶点尝试与未被拒绝过且优先级最高的右顶点匹配,会出现同(1)的两种情况
3.重复(2),直到所有点都被匹配
时间复杂度O(n^2)
换种说法…
1.第一轮,每个男生向自己名单排首位的女生表白,会出现两种情况
(1)该女生没被追求过,则接受该男生
(2)该女生已有男票,则将男票与该男生比较,选她更喜欢的那个…
2.第一轮结束,有些男生有女朋友了,有些仍然单身
每个单身的男生向没拒绝过他,且最喜欢的女生表白,会遇到上述两种情况,解决方案也相同
3.重复该过程,直到所有人都不是单身
3.GS算法实现
#include<bits/stdc++.h>
#define mod 1000000007
#define MAXN 1000
typedef long long ll;
using namespace std;
int ManArray[MAXN][MAXN],GirArray[MAXN][MAXN];//ManArray[i][j]代表编号为i的男生的第j位心仪女生是几号,GirArray[i][j]代表编号为i的女生的第j位心仪男生是几号
int Man[MAXN],Gir[MAXN];//Man[i]代表i号男生所匹配到的女生是几号,Gir[i]代表i号女生所匹配到的男生是几号
int ManStarPos[MAXN];//ManStarPos[i]代表i号男生现在匹配到的女生是他心目中的第几号心仪女生
int n;
stack < int >q;//始终存放没有匹配成功的男生的编号
int GetPositionFromLaday(int GirI,int ManI)//这个函数求的是编号为ManI的男生在编号为GirI的女生的心中的排名顺序
{
for(int i=0;i<n;i++)
if(GirArray[GirI][i]==ManI)
return i;//返回这个顺序
return -1;
}
void ManLookGir(int ManI)//为编号为ManI的男生匹配女生
{
int NowGir=ManArray[ManI][ManStarPos[ManI]];//得到这个男生应该匹配的女生的编号
if(Gir[NowGir]==-1)//如果这个条件满足,说明这个女生没有和她对应匹配的男生,那么就匹配上
{
Man[ManI]=NowGir;
Gir[NowGir]=ManI;
}
else//这个女生现在已经有男朋友了
{
int OldMan=GetPositionFromLaday(NowGir,Gir[NowGir]);//得到现男友在这个女孩心中的排名
int NowMan=GetPositionFromLaday(NowGir,ManI);//得到我们要匹配的男生在这个女孩心中的排名
if(OldMan<NowMan)//如果这个条件满足,说明这个女孩的现男友在这个女孩心中的排名要高于我们要匹配的这个男生的排名,这个女孩不换男朋友
{
ManStarPos[ManI]++;
q.push(ManI);
}
else//这个女孩更喜欢我们要匹配的这个男生,换男朋友
{
ManStarPos[Gir[NowGir]]++;//这是一个优化
q.push(Gir[NowGir]);
Man[ManI]=NowGir;
Gir[NowGir]=ManI;
}
}
}
int main()
{
cin>>n;
memset(Man,-1,sizeof(Man));//初始化这三个数组
memset(Gir,-1,sizeof(Gir));
memset(ManStarPos,0,sizeof(ManStarPos));
for(int i=0;i<n;i++)//输入每个男生心目中对女生的排序
for(int j=0;j<n;j++)
cin>>ManArray[i][j];
for(int i=0;i<n;i++)//输入每个女生心目中对男生的排序
for(int j=0;j<n;j++)
cin>>GirArray[i][j];
for(int i=0;i<n;i++)//刚开始对每个男生都进行一次匹配,从每个男生最心仪的女生开始匹配。如果从程序这个地方进入ManLookGir函数,那么每个男生都会和自己最心仪的女生进行一次匹配,因为是ManStarPos数组决定的,至于能否匹配成功,这就不一定了
ManLookGir(i);
while(!q.empty())
{
int i=q.top();
q.pop();
ManLookGir(i);
}
for(int i=0;i<n;i++)
cout<<"Man NO.: "<<i<<" Laday NO.: "<<Man[i]<<endl;
}