组合数学之稳定婚姻问题

E - Marriage is Stable
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

Albert, Brad, Chuck are happy bachelors who are in love with Laura, Marcy, Nancy. They all have three choices. But in fact, they do have some preference in mind. Say Albert, he likes Laura best, but that doesn't necesarily mean Laura likes him. Laura likes Chuck more than Albert. So if Albert can't marry Laura, he thinks Nancy a sensible choice. For Albert, he orders the girls Laura > Nancy > Marcy. 

For the boys: 

Albert: Laura > Nancy > Marcy 
Brad: Marcy > Nancy > Laura 
Chuck: Laura > Marcy > Nancy 

For the girls: 

Laura: Chuck > Albert > Brad 
Marcy: Albert > Chuck > Brad 
Nancy: Brad > Albert > Chuck 

But if they were matched randomly, such as 

Albert <-> Laura 
Brad <-> Marcy 
Chuck <-> Nancy 

they would soon discover it's not a nice solution. For Laura, she likes Chuck instead of Albert. And what's more, Chuck likes Laura better than Nancy. So Laura and Chuck are likely to come together, leaving poor Albert and Nancy. 

Now it's your turn to find a stable marriage. A stable marriage means for any boy G and girl M, with their choice m[G] and m[M], it will not happen that rank(G, M) < rank(G, m[G])and rank(M, G) < rank(M, m[M]). 

Input

Each case starts with an integer n (1 <= n <= 500), the number of matches to make. 

The following n lines contain n + 1 names each, the first being name of the boy, and rest being the rank of the girls. 

The following n lines are the same information for the girls. 

Process to the end of file. 

Output

If there is a stable marriage, print n lines with two names on each line. You can choose any one if there are multiple solution. Print "Impossible" otherwise. 

Print a blank line after each test. 

Sample Input

3
Albert Laura Nancy Marcy
Brad Marcy Nancy Laura
Chuck Laura Marcy Nancy
Laura Chuck Albert Brad
Marcy Albert Chuck Brad
Nancy Brad Albert Chuck

Sample Output

Albert Nancy
Brad Marcy

Chuck Laura

看着题目非常复杂,可这却是实实在在的组合数学问题

话说在1962年,两个数学家David Gale 和Lloyd Shapley提出了下面的问题:

给定若干个男生和同样多的女生,他们每个人都对所有的异性有一个心理的偏好次序。是否存在一种男女配对组合构成一种稳定的组合关系?这里稳定组合的意思是说,不存在两个非伴侣的异性对彼此的评价比对各自伴侣的评价还要高。(可以理解,这样的异性太容易红杏出墙了,所以是某种不稳定因素。)进一步的问题是,在已知每个人对异性的偏好顺序的情况下,怎样求出这种稳定组合方式(如果它存在的话)?你可以理解为这是数学家们替月老问的问题:给定一群孤男寡女,寻找一种牵红线的方式,以确保把红杏扼杀在摇篮里。

这一问题被称为稳定婚姻问题。它有很多种可能的解法。为了让大家相信数学家不是真得如此无聊,我要指出它确确实实是一个地道的组合数学问题,有其特定的数学价值。当然啦,它也有很多别的背景和应用,比如用来在若干个公司和应聘者之间进行招聘中介……但是数学家们怎么会放过如此八卦的一个名字呢?于是它就这样流传下来了。

给定每个人关于异性的偏好排序,要寻找一种男女配对组合构成稳定的组合。Gale和Shapley不但提出了这个问题本身,而且给出了一种著名的解法。这个解法可以描述为如下的求偶过程:

首先,让这些男生去向他们最心仪的女生求婚——这是数学家们的原本的用词。如果你觉得太快了的话,让我们暂时改成表白吧……

然后,等所有男生表白完毕后,所有的收到表白女生们都从自己的表白者中选择自己最喜欢的人接受为男朋友。没人表白的女生只能暂时等一等了,不要着急,表白会有的。

以上过程称为“一轮”。之后的每一轮都按照类似的方式进行。首先由还处于单身状态的男生们每个人再次向自己还没有表白过的女生中自己最喜欢的人表白(无论人家是否已经有了男朋友),然后,等所有单身男生表白完毕后,所有的收到表白女生们都从自己的表白者中选择自己最喜欢的人接受为男朋友。如果原来有男朋友而表白者中有自己更喜欢的,不要犹豫,换之。等到尘埃落定之后,再开始如上所述的新的一轮表白。

依此类推。可以证明的是,这个过程一定是会终止的,也就是说,不会陷入任何死循环。并且一旦终止,每个人都会找到一个伴侣。更关键的是,这个过程最终得到的一定是如前所述的“稳定组合”:不存在两个非伴侣的异性对彼此的评价比对各自伴侣的评价还要高。——这几个事实都不难证明,有兴趣的话可以自己试试看。

所以这就得到了稳定婚姻问题的一个解(顺便也证明了解的存在性)。但是真正有趣的部分还在后面。一般来说,给定若干个男生女生和他们之间的偏好关系,稳定组合存在不止一种。上述“算法”只是给出了所有可能的稳定组合其中之一而已。但是这个特定的解具有某些特别的性质:可以证明(这一次证明不很容易了),上述方式得到的稳定组合和所有其他的可能的稳定组合相比,是对男生最优而对女生最劣的。

确切地说是这样:

它是对男生最优的。也就是说,对每个男生来说,按照这种方式最后找到的伴侣,是在所有的稳定组合中自己可能具有的伴侣中自己评价最高的。——注意这并不等于说被个男生都能追到自己最喜欢的女生,而只是说,他一定能追到“有可能和他在稳定组合中在一起的女生”中自己最喜欢的。有些女生虽然很好,但是和他在一起是不可能形成稳定组合的。这就是人生啊……

另一方面,它是对女生最劣的。也就是说,对每个女生来说,按照这种方式最后找到的伴侣是在所有的稳定组合中自己可能具有的伴侣中自己评价最低的。同样的,这也不等于说每个女生都只有和自己最不喜欢的男生在一起,而只是说她最后的男朋友会是所有“有可能”的男生中自己觉得最勉强的。不过这样听起来也已经很悲惨了。

这两个结论并不直观,因为看起来在上面所描述的过程中,女生是相对占有优势的。作为男生,需要很辛苦地去不断表白,然后被拒,再表白,再被拒……而女生只要随心所欲挑选就好,而且还有随时更换男友的权利(在上面的规则里男生是不能主动提出分手的)。为什么结局会是如此?

但是如果仔细思考上面所描述的规则,会看到男生至少有一样优势——也许是至关重要的优势:他们是主动方。主动的好处是,即使一次又一次的被拒,他也仍然可以和剩下的女生中自己最喜欢的在一起。而对于女生来说,纵然有再多挑选的自由,可是一个女生也许永远也等不到自己最喜欢的男生来追自己——或者在她等到之前,游戏就已经结束了。

毫无疑问,你已经看出在上面的设定里“男生”和“女生”都只是代号而已,它符合古典文学的一贯叙事,但是在当代语境里也许并不政治正确。另一方面,这个定理也不是真的用来描述爱情的——数学家们还没有这么疯狂,认为可以用逻辑来推理情感。它只是一个过于简化的模型而已,比张生和维特的故事还要不靠谱的多。

但是我也相信你一定已经看出了我这篇文章的主题。在一切古典文学的叙事里,我们都满怀着希望注视着那些勇敢的孩子们,看着他们的努力和坚持,也许最后会失败,可是他们至少尝试过。

现在连数学也在帮着说明这个道理了,你还等什么呢?

**********************************************************************************

这个问题确实是组合数学上的经典问题。具体算法的证明可以参考《组合数学》二分图匹配中的稳定婚姻问题。

这个算确实是在一个偶然的机会下接触到的,但在认真看完书后,确实颇有感想:男生不断地去像女生表白,然后不断地被拒绝···看似十分郁闷,但得到的结果却是在所有可能的结果中对男生最有利的结果。而女生看似十分幸福,但得到的确实是最差的结果。

come from 大牛

ac代码:

#include<cstdio> #include<cstring> #include<string> #include<iostream> #include<map> using namespace std; int n,gp_boy[505][505],gp_girl[505][505],boy[505],girl[505],rank1[505]; map<string,int>mp_boy,mp_girl; string sboy[505],sgirl[505]; char s[1000]; void use() {     memset(girl,0,sizeof(girl));     memset(boy,0,sizeof(boy));     for(int i=1;i<=n;i++)     rank1[i]=1;     while(1)     {         int k=0;         for(int i=1;i<=n;i++)         {             if(!boy[i])             {                 int g=gp_boy[i][rank1[i]++];                 if(!girl[g])                     boy[i] = g, girl[g] = i;                 else if(gp_girl[g][i]>gp_girl[g][girl[g]])                 boy[girl[g]] = 0, girl[g] = i, boy[i] = g;                 k=1;             }         }         if(k==0)         break;     } } int main() {     while(cin>>n)     {         getchar();         mp_boy.clear(),mp_girl.clear();         int tem,pos=1;         for(int i=1; i<=n; i++)         {             scanf("%s",s);             sboy[i] = s,mp_boy[s] = i;             for(int j=1; j<=n; j++)             {                 scanf("%s",s);                 tem=mp_girl[s];                 if(tem == 0)                 mp_girl[s] = tem = pos++; sgirl[tem] = s;                 gp_boy[i][j] = tem;             }         }         for(int i=0;i<n;i++)         {             scanf("%s",s);             int x=mp_girl[s];             for(int j=0;j<n;j++)             {                 scanf("%s",s);                 int y=mp_boy[s];                 gp_girl[x][y]=n-j;             }         }         use();         for(int i=1;i<=n;i++)         cout<<sboy[i]<<' '<<sgirl[boy[i]]<<endl;     }     return 0; }

//sboy[i]存的是输入的第i男生的名字 //sgirl[i]存的是在输入过程中第i个出现的女生的名字(在输入男生的同时女生已经出现) //mp_boy[名字]和sboy反过来存的是名字是第几个男生,mp_girl同 //gp_boy[x][y]=i指的是第x个男生第y的喜欢的女生是sgirl[i]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值