1.问题分析
问题描述:有N男N女,每个人都按照他对异性的喜欢程度排名。现在需要写出一个算法安排这N个男的、N个女的结婚,要求两个人的婚姻应该是稳定的。何为稳定?有两对夫妻M1 F2,M2 F1。M1心目中更喜欢F1,但是他和F2结婚了,M2心目中更喜欢F2,但是命运却让他和F1结婚了,显然这样的婚姻是不稳定的,随时都可能发生M1和F1私奔或者M2和F2私奔的情况。所以在做出匹配选择的时候(也就是结婚的时候),我们需要做出稳定的选择,以防这种情况的发生。要求:boys和girls各自给出自己心仪的嘉宾的顺序,请编写程序求出一种稳定的匹配,使匹配结果不会发生私奔现象。
本题主要是争对从男性优先发出邀约选择,女士来接受或拒绝,匹配的结果对发出邀约方有利,即男性找到的配偶满意度高。
2.问题的解决方案/算法选择/设计思路
2-1.设计思路
每轮男生都要向自己心目中排名最高的女生追求(建立一个数组,数组值记录被追求女生过的排名到哪里了);分别为男女生建立一个二位数组[][j],j为心目之中的排名,其中值为女生号,即哪个女生;女生要存放自己的现男友是谁(建立一个数组,数组值记录女生现在的现男友),用来和追求者相比;男生要存放现女友是谁为了判断有没有男生是单身的(建立一个数组,数组值记录男生的现女友)如果值为0就没有女朋友。
2-2.详细步骤
在最开始输入需要配对的对数num;boyper[num][num]定义一个数组存放女生在男生心中的排位;girlper[num][num]定义一个数组存放男生在女生心中的排位;定义一个q确定数字是否在配对对数范围内;然后输入各个男生女生心目中另一半的排名q,如果q在范围内则带入数组j的位置。
定义一个数组来存放各男女的对象其中i为其对应数组位置,内容为其对象的号,也就是从一开始的号,所以初始化为0代表他们都没有对象;为了保证追求过的不再重复追求,男性渴望追求的偏好女性在不断更新,初始大家都为0 从偏好数组第一位开始 i为这个男生的对应数组位置,内容用于约会女生的对于位置。然后看看有没有男生存在没对象,如果有,按序号遍历所有男生看看谁没有,如果某男士没有对象,优先追求偏好高的女生(在心目中排名靠前的女生),存储当前男生还未追求的最高偏好女性的号即是哪个女生 (boychase),然后判断这个女生有没有现任,如果为boychasebf=0就是没男朋友为其他数字就是男朋友是哪个。如果女孩有现任,然后判断是否稳定,如果被追求女生更喜欢现任!则女孩继续和现任在一起,如果该男生比该男生准备追求的女士的现任在心目中更好,女孩现任变成单身,该男士的对象变成准备追求的女士,女士的对象变成该男士。如果女孩没有现任,女生和追求的男生在一起。然后boyml[i]++该男生的偏好移动,这个女生已经追过,继续循环。循环结束后输出最终结果,谁和谁最终在一起了。
其中有一个current_male_is_better函数,用来比较某女士现在的对象和追求者哪个在她心目中排行更高, 数组参数是一维(是一位女士的优先表而不是所有女士的优先表), rank_of_current, rank_of_chasing是现任排行与追求者排行,将这两者进行比较,如果rank_of_current < rank_of_chasing,则更偏好原对象,相反则更偏向追求者,更新追求者。
3.算法设计/问题求解中所遇到的问题及分析解决方案
一怎么证明算法可以在有限时间内结束?
因为每名男性只可能向特定的女性求婚一次。所以,总的求婚次数最多是n²,n就是男性或女性人数。这个数字是有限的,所以算法必然在有限时间内结束。
二怎么确定算法结束时,每个人都结婚了?
可以用反证法,如果有这种情况,那么存在一个女人,她从来未被求过婚,并且有从未向这个女人求过婚的男人。但这是不可能的,因为如果只剩下这个男人和这个女人没有结婚,那么根据算法,不管这个女人在这个男人的喜好列表里的排名有多低,他还是得向这个女人求婚。所以,算法结束时,所有人都结婚了。
三怎么证明所有婚姻是稳定的?
还是用反证法,如果存在这样两对不稳定夫妻,且不稳定因素是Bob和Alice。那么因为Alice在Bob心目中的排名比其现任妻子高,则Bob必然在现任妻子之前向Alice求婚过。而Alice心目中,Bob的排名比现任丈夫高,则不管其现任丈夫在Bob之前或之后求婚,留下的必然是Bob。所以不可能出现不稳定婚姻。
4. 代码:
#include<stdio.h>
#include<iostream>
bool finish_or_not(int, int *);
bool current_male_is_better(int num, int *girlper, int current, int chasing);
int main(){
int num=0;int i,j;
printf("请输入需要配对的对数:");
scanf("%d",&num);
if(num==0)
{
printf("没有人数无法匹配,请重新输入匹配对数:");
scanf("%d",&num);
}
int boyper[num][num];//定义一个数组存放女生在男生心中的排位
int girlper[num][num];//定义一个数组存放男生在女生心中的排位
int q;//确定数字是否在配对对数范围内
for (int i = 0; i < num; i++){
printf("男生%d心中的女生排行:",i+1);
for (int j = 0; j < num; j++){
scanf("%d",&q);
if(q<=num&&q>0){
boyper[i][j]=q;
}else{
printf("输入错误,请重新输入");
j--;
}
}
}
for (int i = 0; i < num; i++){
printf("女生%d心中的男生排行:",i+1);
for (int j = 0; j < num; j++){
scanf("%d",&q);
if(q<=num&&q>0){
girlper[i][j]=q;
}else{
printf("输入错误,请重新输入");
j--;
}
}
}
//定义一个数组来存放各男女的对象其中i为其对应数组位置,内容为其对象的号,也就是从一开始的号,所以初始化为0代表他们都没有对象
int *girlbf = new int[num];//
int *boygf = new int[num];
for (int i = 0; i < num; i++){
girlbf[i] = 0;
boygf[i] = 0;
}//现任
//为了保证追求过的不再重复追求,男性渴望追求的偏好女性在不断更新
int *boyml= new int[num];
for (int i = 0; i < num; i++){
boyml[i] = 0;//初始大家都为0 从偏好数组第一位开始 i为这个男生的对应数组位置,内容用于约会女生的对于位置
}
while(finish_or_not(num, boygf)==false){//有男生存在没对象
for (int i=0;i<num;i++){//按序号遍历所有男生看看谁没有
if (boygf[i]==0){//如果某男士没有对象
printf("男生%d没有对象,可追求女生!\n",i+1);
//优先追求偏好高的女生
int boychase = boyper[i][boyml[i]];//存储当前男生还未追求的最高偏好女性的号即是哪个女生 (boychase)
//判断这个女生有没有现任
int boychasebf = girlbf[boychase-1];//存储当前追求的女士的对象(boychasebf)(号) 数组位置=号-1 (boychase-1)
printf("男生%d准备追偏好的女生%d\n",i+1,boychase);//i+1号
if (boychasebf!=0){//如果为0就是没男朋友为其他数字就是男朋友是哪个
printf("被追求女生的现任是%d\n", boychasebf);
//判断是否稳定
if (current_male_is_better(num, girlper[boychase-1],boychasebf, i+1)){ //数组,被追求的女性的偏好,当前对象,追求男的号
printf("被追求女生更喜欢现任!\n");//false
}
else{//如果该男生比该男生准备追求的女士的现任在心目中更好 ture
boygf[boychasebf-1]=0;//女孩现任变成单身
boygf[i] =boychase;//该男士的对象变成准备追求的女士
girlbf[boychase-1]=i+1;//女士的对象变成该男士
printf("男生%d横刀夺爱和女生%d在一起了!\n",i+1,boychase);
}
}
else{
printf("被追求的女生是单身\n");
boygf[i] =boychase;//该男士的对象变成准备追求的女士
girlbf[boychase-1]=i+1;//女士的对象变成该男士
printf("男生%d和女生%d在一起了!\n",i+1,boychase);
}
boyml[i]++;//该男生的偏好移动,这个女生已经追过
}
}
}
for (int i=0; i<num;i++){
printf("男生%d和女生%d最后走到一起 \n",i+1,boygf[i]);
}
}
bool finish_or_not(int num, int *boygf){
for (int i=0; i<num;i++){
if (boygf[i]==0){//判断是否全部完成配对
printf("有可配对的单身人士");
return false;
}
}
printf("全部配对完成\n");
return true;
}
//比较某女士现在的对象和追求者哪个在她心目中排行更高
//数组参数是一维(是一位女士的优先表而不是所有女士的优先表)
bool current_male_is_better(int num, int *girlper, int current, int chasing){ //数组,被追求的女性的偏好,当前原来对象,追求男的号
int rank_of_current, rank_of_chasing;//现任排行与追求者排行
for (int i = 0; i < num; i++){
if (girlper[i]==current){
rank_of_current = i+1;//位数
}
if (girlper[i]==chasing){
rank_of_chasing = i+1;
}
}
printf("在女士心目中现任排名是: %d,而追求者排名则是: %d\n",rank_of_current,rank_of_chasing);
if (rank_of_current < rank_of_chasing)
return true;//更偏好原对象
else
return false;//新追求者
}