ZOJ 1576 Marriage is Stable 稳定婚姻问题

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1576

稳定婚姻是组合数学里面的一个问题。

        问题大概是这样:有一个社团里有n个女生和n个男生,每位女生按照她的偏爱程度将男生排序,同时每位男生也按照自己的偏爱程度将女生排序。然后将这n个女生和n个男生配成完备婚姻。如果存在两位女生A和B,两位男生a和b,使得A和a结婚,B和b结婚,但是A更偏爱b而不是a,b更偏爱A而不是B,则这个婚姻就是不稳定的,A和b可能背着别人相伴而走,因为他俩都认为,与当前配偶比起来他们更偏爱各自的新伴侣。如果完备婚姻不是不稳定的,则称其是稳定的。通过证明,可以得到每一个n女n男的社团,都存在稳定婚姻的结论。但是这种情况只在异性的社团中存在。也就是说在同性的社团里面,稳定婚姻的存在性将不再被保证。

      实现该问题的算法是:Gale-Shapley 算法。 其算法的大致思路是:第一轮先让所有的男生选择自己最心仪的女生进行表白,当然这时候有些女生会没有男生没有表白,没事接下去会有的。然后女生在所有向自己表白的男生中选出最心仪的男生作为男朋友。 接下去就是第二轮,该轮还是一样,没有女朋友的男生选择没有拒绝过自己的最心仪的女生进行再一次的表白,不管那个女生有没有男朋友,表白完了之后,又是女生选最心仪的男朋友,对于某个女生,要是她发现现男友没有本轮向自己表白的男生好的话, 就可以选择换点男朋友,如此循环下去就可以将所有的男女生进行配对了。

算法的伪代码:

while  存在男人m是自由的且还没对每个女人都求过婚
      选择这个男人m
                令w是m的优先表中还没求过婚的最高排名的女人
        if  w是自由的  
            (m,w)变成约会状态
        else  w当前与m1约会
              if  w更偏爱m1而不爱m
                                  m保持自由
              else    w更偏爱m而不爱m1
                                        (m,w)变成约会状态
                    m1变成自由
              endif
                  endif
endwhile

代码实现:

#include<stdio.h>
#include<string.h>
#include<map>
#include<iostream>
using namespace std;
int N ;
map<string,int> mp_gg ;
map<string,int> mp_mm ;
string ss ,name[510*2];
int maze_gg[510][510] ;
int maze_mm[510][510] ;
int match_gg[510] , match_mm[510]  ;
int p[510] ;

void solve(){
	memset(match_gg , -1 ,sizeof(match_gg));		//标记男生的对象标号 
	memset(match_mm , -1 ,sizeof(match_mm));		//标记女生的对象编号 
	for(int i=1;i<=N;i++){
		p[i] = 1 ;							//标记男生表白次数 
	}
	bool flag = true ;
	while(flag){
		flag = false ;
		for(int i=1;i<=N;i++){
			if(match_gg[i]==-1 && p[i]<=N){			//男生还单身 
				int a = maze_gg[i][p[i]++] ;
				
				if(match_mm[a]==-1){				//女生也单身 
					match_mm[a] = i ;
					match_gg[i] = a ;
				}
				else{							
					if(maze_mm[a][i] < maze_mm[a][match_mm[a]]){		//本轮的男生更优秀 , 替换 
						match_gg[i] = a ;
						match_gg[ match_mm[a] ] = -1 ;
						match_mm[a] = i ;
					}
				}
				flag = true ;
			}	
		}	
	}
	for(int i=1;i<=N;i++){
		cout << name[i] << " " << name[ N + match_gg[i] ] << endl ;
	}
	cout << endl ;
}
int main(){
	while(cin >> N){
		mp_gg.clear() ;
		mp_mm.clear() ;
		
		int cnt = 0 ;
		for(int i=1;i<=N;i++){
			cin >> ss ;
			mp_gg[ss] = i ;			//男孩的编号 
			name[i] = ss ;			//男孩的名字 
			for(int j=1;j<=N;j++){
				cin >> ss ;
				int num ;
				if(mp_mm[ss] == 0){
					mp_mm[ss] = ++cnt ;		//女孩的编号 
					name[N+cnt] = ss ;		//女孩的名字	
					num = cnt ;
				}
				else{
					num = mp_mm[ss] ;
				}
				maze_gg[i][j] = num ;		//i号男孩第j个心仪女孩的编号 
			}
		}
		for(int i=1;i<=N;i++){
			cin >> ss ;
			int num_mm = mp_mm[ss] ;
			for(int j=1;j<=N;j++){
				cin >> ss ;
				int num_gg = mp_gg[ss] ;
				maze_mm[num_mm][num_gg] = j ;	
			}
		}
		solve();
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值