原文鏈接:http://blog.csdn.net/cscmaker/article/details/8291131
(一)問題的引出:
??????????? 有N男N女,每個人都按照他對異性的喜歡程度排名。現在需要寫出一個算法安排這N個男的、N個女的結婚,要求兩個人的婚姻應該是穩定的。
??????????? 何為穩定?
??????????? 有兩對夫妻M1 F2,M2 F1。M1心目中更喜歡F1,但是他和F2結婚了,M2心目中更喜歡F2,但是命運卻讓他和F1結婚了,顯然這樣的婚姻是不穩定的,隨時都可能發生M1和F1私奔或者M2和F2私奔的情況。所以在做出匹配選擇的時候(也就是結婚的時候),我們需要做出穩定的選擇,以防這種情況的發生。
(二)算法介紹:
?? 參考:http://www.matrix67.com/blog/archives/2976
?? 1962 年,美國數學家 David Gale 和 Lloyd Shapley 發明了一種尋找穩定婚姻的策略。不管男女各有多少人,不管他們各自的偏好如何,應用這種策略后總能得到一個穩定的婚姻搭配。換句話說,他們證明了穩定的婚姻搭配總是存在的。有趣的是,這種策略反映了現實生活中的很多真實情況。
???
??? 算法中采用了男生主動追求女孩的形式。
??? 算法步驟描述:
???? ?? 第一輪,每個男人都選擇自己名單上排在首位的女人,并向她表白。這種時候會出現兩種情況:(1)該女士還沒有被男生追求過,則該女士接受該男生的請求。(2)若該女生已經接受過其他男生的追求,那么該女生會將該男士與她的現任男友進行比較,若更喜歡她的男友,那么拒絕這個人的追求,否則,拋棄其男友(囧)……
? ? ?? 第一輪結束后,有些男人已經有女朋友了,有些男人仍然是單身。
?????? 在第二輪追女行動中,每個單身男都從所有還沒拒絕過他的女孩中選出自己最中意的那一個,并向她表白,不管她現在是否是單身。這種時候還是會遇到上面所說的兩種情況,還是同樣的解決方案。直到所有人都不在是單身。
怎么證明這個算法肯定能夠得到穩定的婚姻:
(1)隨著輪數的增加,總有一個時候所有人都能配上對。因為男生根據自己心目中的排名依次對女士進行表白,假如有一個人沒有配上對,那么這個人必定是向所有的女孩進行表白了。但是女孩只要被表白過一次,就不可能是單身,也就是說此時所有的女生都不是單身的,這與有一個人沒有配上對是相悖的。所以假設不成立。該算法一定會使得所有人都能夠配對成功。
(2)隨著輪數的增加,男士追求的對象越來越糟,而女士的男友則可能變得越來越好。假設男A和女1各有各自的對象,但是比起現在的對象,男A更喜歡女1,所以,在此之前男A肯定已經跟女1表白過的,并且女1拒絕了男A,也就是女1有了比男A更好的男友,不會出現私奔的情況……。
(三)算法實現
- #include<iostream>??
- #include?<stack>??
- ??
- using?namespace?std;??
- ??
- #define?NUM?4??
- #define?NIL?-1??
- ??
- int?GetPositionFromLaday(int?ladayArray[][NUM],?int?laday,?int?man)??
- {??
- ????for(int?i=0;?i<NUM;?i++)??
- ????????if(ladayArray[laday][i]?==?man)??
- ????????????return?i;??
- ????return?NIL;??
- }??
- ??
- void?ChoosePartener(stack<int>&?manStack,?int?manPos,?int?manArray[][NUM],?int?ladayArray[][NUM],?int?manPerfer[],?int?manStartPos[],?int?ladayNow[])??
- {??
- ????//選擇自己名單上排在首位的女人??
- ????????int?perferLaday?=?manArray[manPos][manStartPos[manPos]];??
- ????????//如果該女孩沒有接受過表白,則接受該男孩的表白??
- ????????if(ladayNow[perferLaday]?==?NIL)??
- ????????{??
- ????????????ladayNow[perferLaday]?=?manPos;??
- ????????????manPerfer[manPos]?=?perferLaday;??
- ????????}??
- ????????//如果已經有人向她表白,則判斷其現在擁有的有沒有現在追求的好??
- ????????else??
- ????????{??
- ????????????int?oldPos?=?GetPositionFromLaday(ladayArray,?perferLaday,?ladayNow[perferLaday]);??
- ????????????int?newPos?=?GetPositionFromLaday(ladayArray,?perferLaday,?manPos);???
- ????????????if(oldPos?<?newPos)??
- ????????????{??
- ????????????????manStartPos[manPos]++;//說明該女生更喜歡現在擁有的,選心目中第二位??
- ????????????????//加入單身行列??
- ????????????????manStack.push(manPos);??
- ????????????}??
- ????????????else?//換男友??
- ????????????{??
- ????????????????//被甩的男友恢復自由身份??
- ????????????????manStartPos[ladayNow[perferLaday]]++;??
- ????????????????//加入單身行列??
- ????????????????manStack.push(ladayNow[perferLaday]);??
- ????????????????//將追求的男士改為現任男友??
- ????????????????ladayNow[perferLaday]?=?manPos;??
- ????????????????manPerfer[manPos]?=?perferLaday;??
- ????????????}??
- ????????}??
- }??
- ??
- int?main()??
- {??
- ????int?manArray[NUM][NUM]?={{2,3,1,0},{2,1,3,0},{0,2,3,1},{1,3,2,0}};????
- ????int?ladayArray[NUM][NUM]?=?{{0,3,2,1},{0,1,2,3},{0,2,3,1},{1,0,3,2}};??
- ??
- ????int?manPerfer[NUM]?=?{0};//每位男生選中的女生??
- ????int?manStartPos[NUM]?=?{0};//記錄每位男生選取的是心目中第幾位的女生??
- ????int?ladayNow[NUM]?=?{NIL,NIL,NIL,NIL};//女生對應的男生??
- ??
- ????stack<int>?manStack;?//?還處于單身的男士??
- ??
- ????//進行第一輪迭代,每個男生都選擇自己名單上排在首位的女生。??
- ????for(int?pos=0;?pos<NUM;?pos++)??
- ????{??
- ????????ChoosePartener(manStack,?pos,?manArray,?ladayArray,?manPerfer,?manStartPos,ladayNow);??
- ????}??
- ??
- ????while(manStack.size()!=0)??
- ????{??
- ????????int?manPos?=?manStack.top();??
- ????????manStack.pop();??
- ????????ChoosePartener(manStack,?manPos,?manArray,?ladayArray,?manPerfer,?manStartPos,ladayNow);??
- ????}??
- ??
- ????for(int?i?=0;i<NUM;?++i)??
- ????????cout<<"Man?NO.:?"<<i<<"?Laday?NO.:?"<<manPerfer[i]<<endl;??
- }??

#include<iostream>
#include <stack>using namespace std;#define NUM 4
#define NIL -1int GetPositionFromLaday(int ladayArray[][NUM], int laday, int man)
{for(int i=0; i<NUM; i++)if(ladayArray[laday][i] == man)return i;return NIL;
}void ChoosePartener(stack<int>& manStack, int manPos, int manArray[][NUM], int ladayArray[][NUM], int manPerfer[], int manStartPos[], int ladayNow[])
{//選擇自己名單上排在首位的女人int perferLaday = manArray[manPos][manStartPos[manPos]];//如果該女孩沒有接受過表白,則接受該男孩的表白if(ladayNow[perferLaday] == NIL){ladayNow[perferLaday] = manPos;manPerfer[manPos] = perferLaday;}//如果已經有人向她表白,則判斷其現在擁有的有沒有現在追求的好else{int oldPos = GetPositionFromLaday(ladayArray, perferLaday, ladayNow[perferLaday]);int newPos = GetPositionFromLaday(ladayArray, perferLaday, manPos); if(oldPos < newPos){manStartPos[manPos]++;//說明該女生更喜歡現在擁有的,選心目中第二位//加入單身行列manStack.push(manPos);}else //換男友{//被甩的男友恢復自由身份manStartPos[ladayNow[perferLaday]]++;//加入單身行列manStack.push(ladayNow[perferLaday]);//將追求的男士改為現任男友ladayNow[perferLaday] = manPos;manPerfer[manPos] = perferLaday;}}
}int main()
{int manArray[NUM][NUM] ={{2,3,1,0},{2,1,3,0},{0,2,3,1},{1,3,2,0}}; int ladayArray[NUM][NUM] = {{0,3,2,1},{0,1,2,3},{0,2,3,1},{1,0,3,2}};int manPerfer[NUM] = {0};//每位男生選中的女生int manStartPos[NUM] = {0};//記錄每位男生選取的是心目中第幾位的女生int ladayNow[NUM] = {NIL,NIL,NIL,NIL};//女生對應的男生stack<int> manStack; // 還處于單身的男士//進行第一輪迭代,每個男生都選擇自己名單上排在首位的女生。for(int pos=0; pos<NUM; pos++){ChoosePartener(manStack, pos, manArray, ladayArray, manPerfer, manStartPos,ladayNow);}while(manStack.size()!=0){int manPos = manStack.top();manStack.pop();ChoosePartener(manStack, manPos, manArray, ladayArray, manPerfer, manStartPos,ladayNow);}for(int i =0;i<NUM; ++i)cout<<"Man NO.: "<<i<<" Laday NO.: "<<manPerfer[i]<<endl;
}