【稳定婚姻问题】hdu1522 Marriage is Stable

稳定婚姻描述的是一个非常有意思的问题,关于一个群体中婚姻的稳定性~ 具体可以搜索一下,这里不再介绍。

本题就脱胎于稳定婚姻问题,给出n名男孩和n名女孩,每个男孩对n名女孩有一个“喜爱列表”,越喜欢的处于列表的越前面。要求找出一个稳定的婚姻关系,使得所有人的婚姻关系都稳定。所谓“稳定”,就是指:对于两对夫妻关系A-a, B-b,不应该存在A更喜欢b且b更喜欢A的情形,否则他们就会出轨离婚!

解决稳定混应问题较普遍的是Gale-Shapley 算法:每次从所有男孩中选出一个还没有伴侣的,从最喜爱的女性开始检查他的喜爱女性列表,如果某个女性没有伴侣,或者这名女性比起自己当前的丈夫更喜欢他,那么女性离婚而和他结婚,如此直到最后所有的男孩都有伴侣为止。可以证明,这样得到的完备婚姻是稳定的~ 具体请参考网上的资料。

话说回来,本题输入处理有点麻烦,不过总的关系并不复杂,我就瞎搞了...不过也因此在调试上费了不少时间。。。

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
using namespace std;

const int MAX = 512;
vector<int> gg[MAX], mm[MAX];
map<string, int> mmmap;
map<string, int> ggmap;
bool rej[MAX][MAX];
int match[MAX];
bool vis[MAX];
string mmlist[MAX], gglist[MAX];
int n;

int loc(int a, int b) {
	for (int i = 0; i < n; ++i) {
		if (mm[a][i] == b) return i;
	}
}

void solve() {
    memset(rej, false, sizeof(rej));
    memset(match, -1, sizeof(match));
    memset(vis, false, sizeof(vis));

    bool ok = true;
     while (ok) {
         ok = false;
         for (int i = 1; i <= n; ++i) {
             if (!vis[i]) {
                 for (int j = 0; j < n; ++j) {
				 	int &e = gg[i][j];
                 	if (match[e] == -1) {
                 		vis[i] = true;
                 		match[e] = i;
                 		break;
                 	} else if (!rej[e][i] && loc(e, i) < loc(e, match[e])) {
                 		vis[match[e]] = false;
                 		vis[i] = true;
                 		match[e] = i;
                 		break;
                 	} else {
                 		rej[e][i] = true;
                 	}
                 }
                 ok = true;
             }
         }
     }
     set<pair<string, string> > ans;
     for (int i = 1; i <= n; ++i) {
         ans.insert(make_pair(gglist[match[i]], mmlist[i]));
     }
     for (set<pair<string, string> >::iterator it = ans.begin();
             it != ans.end(); ++it) {
         cout << it->first << " " << it->second << endl;
     }
 }

 int main() {
     cin >> n;
     string name;
     int right = 0;
     for (int i = 1; i <= n; ++i) {
         cin >> name;
         ggmap[name] = i;
         gglist[i] = name;
         for (int j = 1; j <= n; ++j) {
             cin >> name;
             if (mmmap.count(name) == 0) {
                 mmmap[name] = ++right;
                 mmlist[right] = name;
             }
             gg[i].push_back(mmmap[name]);
         }
     }
     for (int i = 1; i <= n; ++i) {
         cin >> name;
         string him;
         for (int j = 1; j <= n; ++j) {
             cin >> him;
             mm[mmmap[name]].push_back(ggmap[him]);
         }
     }
     solve();

     return 0;
 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值