Problem
在一个盛大的校园舞会上有 n 位男生和 n 位女生,每人都对每个异性有一个排序,代表对他们的喜欢程度。你的任务是将男生和女生一一配对(每人恰好有一个舞伴),使得男生 u 和女生 v 不存在以下情况:(1)男生 u 和女生 v 不是舞伴;(2)他们喜欢对方的程度都大于喜欢各自当前舞伴的程度。如果出现了(2)中的情况,他们可能会擅自抛下自己的舞伴,另外组成一对。
Gale-Shapley算法
- 每一轮每一个尚未订婚的男士向自己当前好感度最高且还未向其求过婚的女士求婚,然后女士在向她求婚的人中选择好感度最高的订婚(可抛弃当前订婚对象)。
- 稳定性:假设存在不合法情况,其相应的合法情况一定出现在该不合法情况前(因为男士按好感度从高到低求婚,女士与先与好感度更高的男士订婚后不会接受低好感度男士的求婚)。
- 最后的方案是完备的,即不存在某位男士没有未婚妻。
- 至多n轮所有男士都会拥有未婚妻,算法时间复杂度O(N2)。
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1005;
int t,n,ladies[maxn][maxn],mans[maxn][maxn],cp[maxn],cnt[maxn],ans,iscp[maxn],recp[maxn];
queue<int>op[maxn];
void choice(int x)
{
if(!cp[x]&&!op[x].empty()) ans++;
while(!op[x].empty())
{
int u = op[x].front();
op[x].pop();
if(mans[x][cp[x]]>mans[x][u]||!cp[x])
{
iscp[cp[x]] = 0;
iscp[u] = 1;
cp[x] = u;
recp[u] = x;
}
}
}
void solve()
{
while(ans!=n)
{
for(int i=1;i<=n;i++)
{
if(cnt[i]!=n&&!iscp[i])
op[ladies[i][++cnt[i]]].push(i);
}
for(int i=1;i<=n;i++)
choice(i);
}
for(int i=1;i<=n;i++)
cout<<recp[i]<<endl;
}
void init()
{
memset(cnt,0,sizeof(cnt));
memset(cp,0,sizeof(cp));
memset(iscp,0,sizeof(iscp));
ans = 0;
}
int main()
{
// freopen("1.txt","w",stdout);
cin>>t;
bool ed = 0;
while(t--)
{
if(ed) cout<<endl;
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&ladies[i][j]);
for(int i=1;i<=n;i++)
{
for(int j=1,k;j<=n;j++)
{
scanf("%d",&k);
mans[i][k] = j;
}
}
solve();
ed = 1;
}
return 0;
}