其实这个东西比较好玩……
意义比较深远……
尤其是对广大屌丝和穷搓矮和魔法师而言……
这个问题在组合数学第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; }