poj 3487

The Stable Marriage Problem
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 1959   Accepted: 835

Description

The stable marriage problem consists of matching members of two different sets according to the member’s preferences for the other set’s members. The input for our problem consists of:

  • a set M of n males;
  • a set F of n females;
  • for each male and female we have a list of all the members of the opposite gender in order of preference (from the most preferable to the least).

A marriage is a one-to-one mapping between males and females. A marriage is called stable, if there is no pair (m,f) such that f ∈ F prefers m ∈ M to her current partner andm prefers f over his current partner. The stable marriage A is called male-optimal if there is no other stable marriage B, where any male matches a female he prefers more than the one assigned in A.

Given preferable lists of males and females, you must find the male-optimal stable marriage.

Input

The first line gives you the number of tests. The first line of each test case contains integer n (0 < n < 27). Next line describes n male and n female names. Male name is a lowercase letter, female name is an upper-case letter. Then go n lines, that describe preferable lists for males. Next n lines describe preferable lists for females.

Output

For each test case find and print the pairs of the stable marriage, which is male-optimal. The pairs in each test case must be printed in lexicographical order of their male names as shown in sample output. Output an empty line between test cases.

Sample Input

2
3
a b c A B C
a:BAC
b:BAC
c:ACB
A:acb
B:bac
C:cab
3
a b c A B C
a:ABC
b:ABC
c:BCA
A:bac
B:acb
C:abc

Sample Output

a A
b B
c C

a B
b A
c C
 
來自網上某大牛:
穩定婚姻問題(The Stable Marriage Problem)” 大致說的就是100個SSGG和100個PPMM按照自己的喜歡程度給所有異性打分排序。每個帥哥都憑自己好惡給每個MM打分:我最愛a,其次愛b,再次愛c...每個帥哥打的分不同,你最愛的可能是我最討厭的我最愛的可能是他不甚喜歡的。同樣,每個美女也同樣給每個帥哥打分。現在需要給他們搭配出100 對新郎新娘,並且要保證所得到是穩定婚姻的搭配。那麼,什麼是不穩定的婚姻呢?所謂不穩婚姻是說, 比如說有兩對夫婦(M1、F1)和(M2、F2),M1的老婆是F1,但他更愛F2;而F2的老公雖說是M2,但她更愛M1——這樣的婚姻就是不穩婚姻,M1和F2理應結合,他們現在各自的婚姻都是錯誤。 

那麼,我們如何找到一個算法來構造這100個穩定婚姻呢?這個是數學界切切實實研究過的問題。對於以前沒有接觸過這個問題的人,這個理論最出人意外的結論是: 傳統的求愛、結婚過程是male-optimal(男生主動)的,也就是說,男性能夠得到儘可能好的心上人,女性卻不然。這個問題和圖論有關, 最早是由兩個美國數學家1962年在American Mathematical Monthly上提出的,相關的參考文獻其實很多,下面這個網頁大概是講得最通俗易懂的: "The Stable Marriage Problem" by Harry Mairson,http://www.cs.columbia.edu/~evs/intro/stable/writeup.html 

那麼,開始激動人心求婚過程啦 

第一天上午, 所有的男生都向自己最愛的美眉求婚。下午,每個MM看看自己有沒有收到, 收到了多少人的求婚。如果只收到一個男生的求婚,那麼就和他訂婚。如果收到多於一個GG的求婚,那麼就和其中她最愛的那個男人訂婚,同時把其他男人都拒掉。如果一個求婚都沒有,不要着急,最後總會有的。晚上,檢查一遍,如果所有MM都訂婚了,OK,萬事大吉,明天舉行集體婚禮! 

但如果還有人沒有訂婚,那麼事情還沒有完,第二天還得重複。 

第二天上午,所有還沒訂婚的男生向自己次愛的美眉求婚(因爲昨天已經被他們的最愛拒絕了)下午,每個MM再看一遍自己收到訂婚的情況。如果她已經訂婚了,但是又有一個她更愛的男人來向她求婚,那就把原來那個拒絕掉,再和這個更愛的男人訂婚;如果還沒訂婚,那就和第一天的下午的處理一樣。晚上再檢查一遍,如果還是有人沒有訂婚,那第三天再重複。 

第三天上午,所有沒有訂婚的GG,包括第一天訂了第二天又被踹出來的(看來要有點憂患意識),再向還沒有拒絕過他的MM中他最愛的那個求婚 

...... 
如此周而復始,直到最後大家都訂了婚,便一起結婚!哈哈,恭喜恭喜 這麼個過程,數學上可以證明如下性質: 
1) 這個過程會中止,也就是說,總有大家都訂了婚的一天,不可能無限循環。 
2) 中止後所有的婚姻是穩定婚姻。我們能證明的是,通過上面那個求婚過程,所有的婚姻都是穩定的,沒有人犯錯誤。 
3) 比較引人注目的是,這個過程是male-optimal(男生主動)的,男性能夠獲得儘可能好的伴侶,比如說最後有二十個女人拒絕了他,他仍然能夠得到剩下的八十個女人中他最愛的那一個。 
4) 更有甚者,這個過程是female-pessimal的,女人總是在可能的情況下被最不喜歡的人追上:eek:。這一點沒有那麼直觀的理解,勉強要解釋的話,可以這麼看:雖說女人每換一次訂婚對象,都往上升一層,但起點可能很低,雖說在一步步接近她最愛的目標,但最後往往達不到。比如說還差三十名就達到她最愛的人了,但這時Game Over,所有的人都已訂了婚,這樣她也只能死了心了!還有三十個她更愛的人還沒向她求過婚,可是她也無可奈何了... 
 
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define maxn 30
int a[200];//a[a+i]表示男士a+i的編號爲i,a[A+j]表示女士A+j的編號爲j
int prefer_male[maxn][maxn],prefer_female[maxn][maxn];//男女士偏好表
int match_female[maxn],match_male[maxn];//記錄男女士現任女男友的編號
int lettle[maxn][maxn];//表示女士i今天收到的第j封信的作者編號(即對第i女士表白的第j個男士的標號)
int num_lettle[maxn];//記錄第i天的信的數量
int curpoint[maxn];//記錄男士下一次表白的女士
int n;
bool finish()//所有男士都有女友結束
{
    for(int i=0; i<n; i++)
        if(match_male[i]==-1)
            return false;
    return true;
}
int find_pos(int male,int female)//返回女士對男士的評價值
{
    for(int i=0; i<n; i++)
        if(male==prefer_female[female][i])
            return i;
}
void solve()
{
    int i,j;
    memset(match_male,-1,sizeof(match_male));
    memset(match_female,-1,sizeof(match_female));
    memset(curpoint,0,sizeof(curpoint));
    while(!finish())
    {
        memset(num_lettle,0,sizeof(num_lettle));
        memset(lettle,-1,sizeof(lettle));
        for(i=0; i<n; i++)//男士表白寫信
        {
            if(match_male[i]==-1)
            {
                lettle[prefer_male[i][curpoint[i]]][num_lettle[prefer_male[i][curpoint[i]]]++]=i;
                //prefer_male[i][curpoint[i]表示第i個男士第curpoint[i]個喜歡的女士編號
                //num_lettle[prefer_male[i][curpoint[i]]]表示該女士收到信的個數
                //整天表示該女士一天收到信的作者編號
                curpoint[i]++;
            }
        }
        for(i=0; i<n; i++)//女士看信
        {
            if(match_female[i]==-1&&num_lettle[i]==1)//只有一個人表白,女士別無選擇了
            {
                match_female[i]=lettle[i][0];
                match_male[lettle[i][0]]=i;
            }
            else if(match_female[i]==-1&&num_lettle[i]>1)//多個人表白,女士要選自己最喜歡的了
            {
                int favor=lettle[i][0];
                for(j=1; j<num_lettle[i]; j++)
                {
                    if(find_pos(lettle[i][j],i)<find_pos(favor,i))
                        favor=lettle[i][j];
                }
                match_female[i]=favor;
                match_male[favor]=i;
            }
            else if(match_female[i]!=-1&&num_lettle[i]!=0)//女士已經有男友,但是還是收到表白信,
            {                                            //她會再重新選擇自己最喜歡的,現任男友就被甩了,囧啊!
                int favor=-1;
                for(j=0; j<num_lettle[i]; j++)
                {
                    if(find_pos(lettle[i][j],i)<find_pos(match_female[i],i))
                        favor=lettle[i][j];
                }
                if(favor!=-1)
                {
                    match_male[match_female[i]]=-1;//被甩了~~~~
                    match_female[i]=favor;//新人成對,O(∩_∩)O~
                    match_male[favor]=i;
                }
            }
        }
    }
}
int main()
{
    int t;
    char temp;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0; i<n; i++)//輸入編號
        {
            cin>>temp;
            a[temp]=i;
        }
        for(int j=0; j<n; j++)
        {
            cin>>temp;
            a[temp]=j;
        }
        for(int i=0; i<n; i++)//男女士對異性評價值
        {
            cin>>temp;
            int male=temp;
            cin>>temp;
            for(int j=0; j<n; j++)
            {
                cin>>temp;
                prefer_male[a[male]][j]=a[temp];
            }
        }
        for(int i=0; i<n; i++)
        {
            cin>>temp;
            int female=temp;
            cin>>temp;
            for(int j=0; j<n; j++)
            {
                cin>>temp;
                prefer_female[a[female]][j]=a[temp];
            }
        }
        solve();
        for(int i=0; i<n; i++)//輸出,挺有才
            for(int j='a'; j<='z'; j++)
            {
                if(a[j]==i)
                {
                    putchar(j);
                    putchar(' ');
                    int index=match_male[i];
                    for(int k='A'; k<='Z'; k++)
                        if(a[k]==index)
                        {
                            putchar(k);
                            break;
                        }
                    cout<<endl;
                    break;
                }
            }
        if(t!=0)
            cout<<endl;
    }
    return 0;
}
另附一連接:用(穩定婚姻 Gale-Shapley算法 )


 
發佈了99 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章