【UVAlive 3989】 Ladies' Choice (稳定婚姻问题)

Ladies' Choice

Teenagers from the local high school have asked you to help them with the organization of next year’s
Prom. The idea is to find a suitable date for everyone in the class in a fair and civilized way. So,
they have organized a web site where all students, boys and girls, state their preferences among the
class members, by ordering all the possible candidates. Your mission is to keep everyone as happy as
possible. Assume that there are equal numbers of boys and girls.
Given a set of preferences, set up the blind dates such that there are no other two people of opposite
sex who would both rather have each other than their current partners. Since it was decided that the
Prom was Ladies’ Choice, we want to produce the best possible choice for the girls.

Input
Input consists of multiple test cases the first line of the input contains the number of test cases.
There is a blank line before each dataset.
The input for each dataset consists of a positive integer N, not greater than 1,000, indicating the
number of couples in theclass. Next, there are N lines, each onecontaining the all the integers from 1
to N,ordered according to the girl’s preferences. Next, there are N lines, each one containing all the
integers from 1 to N, ordered according to the boy’s preferences.

Output
The output for each dataset consists of a sequence of N lines, where the i-th line containsthe number
of the boy assigned to the i-th girl (from 1 to N).
Print a blank line between datasets.
Sample Input
1
5
1 2 3 5 4
5 2 4 3 1
3 5 1 2 4
3 4 2 1 5
4 5 1 2 3
2 5 4 1 3
3 2 4 1 5
1 2 4 3 5
4 1 2 5 3
5 3 2 4 1
Sample Output
1
2
5
3
4

 

 

【题意】

  有n对男女,先给出每个女生对n位男生的选择意向,排在前面的优先选择,然后给出n位男生的选择意向,排在前面的优先选择. 
  输出每位女生的匹配,使得每位女生都是稳定的最佳选择.

 

【分析】

  这是著名的稳定婚姻问题。

  

  1962年,美国数学家David Gale和Lloyd Shapley发明了一种寻找稳定婚姻的策略,人们称之为延迟认可算法(Gale-Shapley算法)。
  先对所有男士进行落选标记,称其为自由男。当存在自由男时,进行以下操作:
  ①每一位自由男在所有尚未拒绝她的女士中选择一位被他排名最优先的女士;
  ②每一位女士将正在追求她的自由男与其当前男友进行比较,选择其中排名优先的男士作为其男友,即若自由男优于当前男友,则抛弃前男友;否则保留其男友,拒绝自由男。
  ③若某男士被其女友抛弃,重新变成自由男。
  在算法执行期间,自由男们主动出击,依次对最喜欢和次喜欢的女人求爱,一旦被接受,即失去自由身,进入订婚状态;而女人们则采取“守株待兔”和“喜新厌旧”策略,对前来求爱的男士进行选择:若该男子比未婚夫强,则悔婚,选择新的未婚夫;否则拒绝该男子的求婚。被女友抛弃的男人重获自由身,重新拥有了追求女人的权利——当然,新的追求对象比不过前女友。
这样,在算法执行期间,每个人都有可能订婚多次——也有可能一开始就找到了自己的最爱,从一而终——每订一次婚,女人们的选择就会更有利,而男人们的品味则越来越差。只要男女生的数量相等,则经过多轮求婚,订婚,悔婚和再订婚之后,每位男女最终都会找到合适的伴侣——虽然不一定是自己的最爱(男人没能追到自己的最爱,或女人没有等到自己的最爱来追求),但绝对不会出现“虽然彼此相爱,却不能在一起”的悲剧,所有人都会组成稳定的婚姻。
  为什么这样稳定?因为这样子进行求婚与拒绝,是不会出现不稳定的情况的。
 
  
  数学上可以证明:
  第一,这个过程会中止,也就是说,总有大家都订了婚的一天,不可能无限循环。
  第二,中止后所有的婚姻是稳定婚姻。所谓不稳婚姻是说,比如说有两对夫妇M1,F1和M2,F2,M1的老婆是F1,但他更爱F2;而F2的老公虽说是M2.但她更爱M1,这样的婚姻就是不稳婚姻,M1和F2理应结合,他们现在各自的婚姻都是错误.我们能证明的是,通过上面那个求婚过程,所有的婚姻都是稳定的,没有人犯错误
  第三,比较引人注目的是,这个过程是male-optimal的,男性能够获得尽可能好的伴侣,比如说最后有二十个女人拒绝了他,他仍然能够得到剩下的八十个女人中他最爱的那一个。
  第四,更有甚者,这个过程是female-pessimal的,女人总是在可能的情况下被最不喜欢的人追上。这一点没有那么直观的理解,勉强要解释的话,可以这么看:虽说女人每换一次订婚对象,都往上升一层,但起点可能很低,虽说在一步步接近她最爱的目标,但最后往往达不到。比如说还差三十名就达到她最爱的人了,但这时GameOver,所有的人都已订了婚,这样她也只能死了心了。还有三十个她更爱的人还没向她求过婚,可是她也无可奈何了,他仍然能够得到剩下的八十个女人中他最爱的那一个

  

  这题要求女士的最优选择,所以把男女反过来就好了。

 

 

2016-10-26 17:11:48

 

 


 

其实只要理解过程,代码是很好打的,来一个有解释的模版;

稳定婚姻问题:

 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 1010

int ml[Maxn][Maxn],rk[Maxn][Maxn];
//ml[i][j]男士i心中排第j的女士是谁
//rk[i][j]女士i心中男士j排名第几
int fh[Maxn],fw[Maxn],nt[Maxn];
//fh[i]女士i的未婚夫 fw[i]男士i的未婚妻(若还没订婚则为0) nt[i]男士i下一次应该向谁求婚

queue<int > q;

void engage(int x,int y) //让男士x和女士y订婚 并且解除女士y之前的婚约(若有)
{
    int z=fh[y];
    if(z)
    {
        fw[z]=0;
        q.push(z);
    }
    fw[x]=y;fh[y]=x;
}

int n;

void init()
{
        scanf("%d",&n);
        while(!q.empty()) q.pop();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
             scanf("%d",&ml[i][j]);
            nt[i]=1;
            fw[i]=0;
            q.push(i);
        }
        
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                int x;
                scanf("%d",&x);
                rk[i][x]=j;
            }
            fh[i]=0;
        }
}

void ffind()
{
    while(!q.empty())
    {
        int x=q.front();q.pop(); //未订婚男士求婚
        int y=ml[x][nt[x]++];
        if(fh[y]==0||rk[y][x]<rk[y][fh[y]])
            engage(x,y);
        else q.push(x);//若求婚失败,则下次再来
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        ffind();
        for(int i=1;i<=n;i++) printf("%d\n",fw[i]);//输出的是男士可能结婚的女士中最优的一个
        if(T) printf("\n");
    }
    return 0;
}
稳定婚姻问题

 

posted @ 2016-10-26 17:07  konjak魔芋  阅读(248)  评论(0编辑  收藏  举报