Stable Matching Problem稳定匹配问题-----稳定婚姻算法

原文地址“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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
稳定匹配问题是一个经典的算法问题,其中Gale-Shapley算法是一种常用的解决方案。下面我简要介绍如何使用C语言编写程序来求解稳定匹配问题。 首先,我们需要定义一个结构体来表示每个人的偏好列表和当前匹配状态。偏好列表可以用整数数组来表示,数组的索引表示其他人的编号,数组的值表示对这个人的偏好等级。例如,假设有n个人,我们可以定义一个结构体如下: ```c typedef struct { int n; // 人数 int **preference; // 偏好列表 int *matching; // 当前匹配 } MatchingProblem; ``` 然后,我们可以使用如下的Gale-Shapley算法来求解稳定匹配问题: 1. 初始化所有人的匹配状态为空。 2. 循环直到没有人再能够改变匹配状态为止: a. 对于每个未匹配的人,选择他偏好列表中的下一个候选人,记为当前候选人。 b. 如果当前候选人未匹配,则直接将其与该人匹配。 c. 如果当前候选人已经匹配,判断当前候选人是否更优于当前匹配。如果是,将当前匹配与当前候选人匹配,将原先与当前候选人匹配的人重新放回未匹配状态。 3. 输出每个人的匹配结果。 在C语言中,我们可以使用指针和动态内存分配来操作偏好列表和当前匹配状态。具体实现可以参考下面的伪代码: ```c void gale_shapley(MatchingProblem *problem) { int *proposals = malloc(sizeof(int) * problem->n); // 存储每个人的偏好索引 int *acceptances = malloc(sizeof(int) * problem->n); // 存储每个人的匹配状态 // 初始化匹配状态和偏好索引 for (int i = 0; i < problem->n; i++) { acceptances[i] = -1; // -1表示未匹配状态 proposals[i] = 0; // 初始化偏好索引为0 } while (1) { // 查找未匹配的人 int unmatched = -1; for (int i = 0; i < problem->n; i++) { if (acceptances[i] == -1) { unmatched = i; break; } } if (unmatched == -1) { // 所有人都已匹配 break; } // 获取当前候选人 int current = problem->preference[unmatched][proposals[unmatched]]; proposals[unmatched]++; if (acceptances[current] == -1) { // 当前候选人未匹配 acceptances[current] = unmatched; acceptances[unmatched] = current; } else if (problem->preference[current][unmatched] < problem->preference[current][acceptances[current]]) { // 当前候选人更优 acceptances[acceptances[current]] = -1; // 原来的匹配放回未匹配状态 acceptances[current] = unmatched; acceptances[unmatched] = current; } } // 输出匹配结果 for (int i = 0; i < problem->n; i++) { printf("Person %d is matched with Person %d\n", i, acceptances[i]); } free(proposals); free(acceptances); } ``` 通过以上的程序,我们可以使用Gale-Shapley算法来求解稳定匹配问题。该算法具有良好的时间复杂度,并且可以保证返回的匹配结果是稳定的。希望这个回答可以帮助你理解如何使用C语言编写程序来求解稳定匹配问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值