关于稳定婚姻问题

其实这个东西比较好玩……

意义比较深远……

尤其是对广大屌丝和穷搓矮和魔法师而言……

这个问题在组合数学第9章出现

问的是:

n男n女,每个男的对每个女的有一个评分,每个女的对每个男的有一个评分,然后……

他们两两配对……

当然结婚以后有可能不幸福,所以希望找到一种配对方案,满足

不存在这样的一对(狗)男女,他们不在一起,同时对对方的评分比对自己配偶高……如果这样他们就会私奔啊私奔~~~~


这个很明显是二分图,但是不是单纯的二分图……

有一个Gale-Shapley算法(应该是叫这两个名字的两个人提出的),又称延迟认可算法

有两种做法,一种男性最优,一种女性最优

以男性最优为例:

①每一个男生向自己评分最高且没拒绝过自己的女性求婚(有可能有女性获得多个人的求婚)

②如果有女性获得多个人的求婚(即使已经订婚),那么挑选自己评分最高的,与其订婚,拒绝其他人

注意在②中,如果有女性已经订婚,那么她会比较订婚的人和向自己提出请求的人,选择评分高的那一个(这就是为什么是“订婚”而非结婚)

算法的正确性随便google一下就有

我想说的是为什么这个方案男性最优……一开始我也没太弄清

这与我们平常的观念不符——如果一个女生很受欢迎,那么她更容易挑到自己满意的人


但是有一点,有可能女生心仪的男生并不喜欢她,因此没能向她求婚

举个例子,有可能n个男生互相不是情敌,那么第一轮求婚以后,算法就结束了,此时每个男生都心满意足,而女生不一定……

然后接下来每次男生求婚都是挑的他觉得最好而且自己有机会的,而女生等啊等有可能都等不到想要的那个人……

而且需要注意的是稳定婚姻问题一定有解(就像屌丝最终会找到一个黑木耳……)



这给我们一个启示……手快有手慢无,一定要主动啊主动~~~~


特别说明以上对基佬不适用……(说不定也适用??)


题目有POJ3487,ZOJ1576,NOJ1710(南开大学OJ……第一次听说)

题目都差不多,都是裸的,输入的处理可能麻烦点(ZOJMS最麻烦,得用map……虽然实际上也比较好写)


POJ3487code:

//其实在处理被拒绝的男生的时候可以开队列,应该可以加快速度,但是事后才想起,就算了……反正数据范围小……

//在处理字符这一点上自认为写的很丑……暴丑……其实可以把数组开大,就可以不用减'A'了,当时有点脑残……

//Lib
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
using namespace std;
//Macro
#define rep(i,a,b) for(int i=a,tt=b;i<=tt;++i)
#define drep(i,a,b) for(int i=a,tt=b;i>=tt;--i)
#define erep(i,e,x) for(int i=x;i;i=e[i].next)
#define irep(i,x) for(__typedef(x.begin()) i=x.begin();i!=x.end();i++)
#define read() (strtol(ipos,&ipos,10))
#define sqr(x) ((x)*(x))
#define pb push_back
#define PS system("pause");
typedef long long ll;
typedef pair<int,int> pii;
const int oo=~0U>>1;
const double inf=1e20;
const double eps=1e-6;
string name="",in=".in",out=".out";
//Var
class P
{
public:
	bool exist;int married;
	int pri[60];
}person[60];
int n,pos[60],T;
void Init()
{
	memset(person,0,sizeof person);
	scanf("%d\n",&n);char ch,s[30];
	rep(i,1,n<<1)
		scanf("%c%*c",&ch),person[ch-'A'+1].exist=true;
	scanf("\n");
	rep(i,1,n)
	{
		scanf("%s",s+1);
		rep(i,3,strlen(s+1))
			person[s[1]-'A'+1].pri[i-2]=s[i]-'A'+1;
		pos[s[1]-'A'+1]=1;
	}
	rep(i,1,n)
	{
		scanf("%s",s+1);
		rep(i,3,strlen(s+1))
			person[s[1]-'A'+1].pri[s[i]-'A'+1]=i-2;
		person[s[1]-'A'+1].pri[0]=oo;
	}
}
void Set(int first,int second,int third)
{
	person[first].married=second;
	person[second].married=first;
	person[third].married=0;
}
void Work()
{
	int cnt=n;
	while(cnt)
	{
		rep(i,'a'-'A'+1,'z'-'A'+1)
		{
			if(person[i].exist&&!person[i].married)
			{
				int t=person[i].pri[pos[i]++];
				if(person[t].pri[i]<person[t].pri[person[t].married])
				{
					if(!person[t].married)cnt--;
					Set(t,i,person[t].married);
				}
			}
		}
	}
	rep(i,'a','z')
	{
		if(person[i-'A'+1].exist)
			printf("%c %c\n",i,person[i-'A'+1].married+'A'-1);
	}
}
int main()
{
//	freopen((name+in).c_str(),"r",stdin);
//	freopen((name+out).c_str(),"w",stdout);
	for(scanf("%d",&T);T;T--)
	{
		Init();
		Work();
		puts("");
	}
	return 0;
}


你可能感兴趣的:(算法,String,Google,OO,BI,System)