稳定婚配问题:n个男生n个女生。当中每一个人都有自己心仪的列表。
问怎样达成稳定的匹配(比方, b想B求婚,可是B已有的对象的优先级高于b,此时b的魅力不足以拆散B所处的那一对,即达到稳定状态。)
(Gale_Shapley algorithm)整体策略:男士负责求婚,女士负责接受或者拒绝。
题目原型: HDUOJ 1914 The Stable Marriage Problem
下面为数据生成函数,生成boys_rankings.txt 和 girls_rankings.txt
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <sstream> #include <algorithm> #include <vector> #include <ctime> #include <fstream> using namespace std; vector<string> gen_boys(int number) { vector<string> result; for(int i = 0; i < number; i++){ string boy = "B"; string s; stringstream ss; ss << i; ss >> s; boy.append(s); result.push_back(boy); } return result; } vector<string> gen_girls(int number) { vector<string> result; for(int i = 0; i < number; i++){ string boy = "G"; string s; stringstream ss; ss << i; ss >> s; boy.append(s); result.push_back(boy); } return result; } vector<string> gen_ranking(vector<string> candidate) { random_shuffle(candidate.begin(), candidate.end()); return candidate; } void write_rankings(vector<string> people, vector<vector<string> > rankings, string out_file) { ofstream ofs(out_file.c_str()); if(ofs.fail()){ cerr << "Error: " << out_file << endl; return; } for(int i = 0; i < people.size(); i++){ ofs << people[i] << ":"; for(int j = 0; j < rankings[i].size(); j++){ ofs << " " << rankings.at(i).at(j); } ofs << endl; } ofs.close(); } int main(int argc, char ** argv) { srand(time(NULL)); int n = 200; vector<string> boys = gen_boys(n); vector<string> girls = gen_girls(n); vector<vector<string> > boys_rankings; vector<vector<string> > girls_rankings; for(int i = 0; i < n; i++){ boys_rankings.push_back(gen_ranking(girls)); girls_rankings.push_back(gen_ranking(boys)); } write_rankings(boys, boys_rankings, "boys_rankings.txt"); write_rankings(girls, girls_rankings, "girls_rankings.txt"); return 1; }
下面为Gale_Sharpley算法实现:
/****************************************************** * Projects : Implementation of Gale_Shapley algorithm * Author : johnsondu * Time : 2014-10-20 21:18 *******************************************************/ #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <fstream> #include <map> #include <vector> #include <cstring> #include <string> using namespace std; // The max size of the number of the boy. const int MAXN = 1000; // STL map, map boy's name to integer ID map<string, int> boy; // STL map, map girl's name to integer ID map<string, int> girl; // STL map, map corresponding boy's integer id to original string name map<int, string> boyName; // STL map, map corresponding girl's integer id to original string name map<int, string> girlName; // boy's preference ranking list int boysRankings[MAXN][MAXN]; // girl's preference ranking list int girlsRankings[MAXN][MAXN]; // the partner that boy matched. if no, marked as -1 int boysPartner[MAXN]; // the partner that girl matched. if no, marked as -1 int girlsPartner[MAXN]; /******************************************************* * function description: * let every boy and girl have it's own integer identity. * key variable: <string, int>(map string name to integer * id), <int, string>(map integer id to original string * name) ********************************************************/ void SerialNumber(int &n) { ifstream in1("boys_rankings.txt"); ifstream in2("girls_rankings.txt"); string str; int idb = 0; // boy's id int idg = 0; // girl's id while(getline(in1, str)){ string name = ""; int i = 0; // get boys's name while(str[i] != ':') name += str[i ++]; // map string to int. boy[name] = idb ; boyName[idb] = name; idb ++; // get the number of boys. n ++; } while(getline(in2, str)){ string name = ""; int i = 0; // get boys's name while(str[i] != ':') name += str[i ++]; // map string to int. girl[name] = idg; girlName[idg] = name; idg ++; } return; } /********************************************* * function description: * Rereading two files, and get corresponding * preference list of boys and girls. Save it * in two dimension array: girlsRankings and * boysRankings. *******************************************/ void GetRankings(const int n) { ifstream in1("boys_rankings.txt"); ifstream in2("girls_rankings.txt"); string str; // boy's id. int id = 0; while(getline(in1, str)){ string gname; int i = 0; int cnt = 0; while(str[i] != ' ') i ++; if(str[i] == ' ') i ++; for(; i < str.size();) { gname = ""; while(str[i] != ' ' && i < str.size()) { gname += str[i]; i ++; } boysRankings[id][cnt ++] = girl[gname]; if(str[i] == ' ') i ++; } id ++; } // girls id; id = 0; while(getline(in2, str)){ string bname; // string size index. int i = 0; // the rankings in the girl's list. int cnt = 0; // prefix guarantee while(str[i] != ' ') i ++; if(str[i] == ' ') i ++; for(; i < str.size();) { bname = ""; while(str[i] != ' ' && i < str.size()) { bname += str[i]; i ++; } girlsRankings[id][cnt ++] = boy[bname]; if(str[i] == ' ') i ++; } id ++; } return ; } /************************************* * function description: * set status for boys and girls, * marked -1, no partner. **************************************/ void InitStatus(const int n) { for(int i = 0; i < n; i ++) { boysPartner[i] = -1; girlsPartner[i] = -1; } } /**************************************** * function description: * when one boy propose to one girl, and * that girl already have a partner, this * function is used for get ratings of * two boys in that girl's preference list. *****************************************/ int GetId(int boyId, int gId, const int n) { for(int i = 0; i < n; i ++) { if(girlsRankings[gId][i] == boyId) return i; } return -1; } /**************************************** * function description: * once a man have dumped by a girl, set * his status to no partner, and set his * preference list of that girl as -1, * stand for have been proposed before. *****************************************/ void SetStatus(int boyId, int girlId, const int n) { boysPartner[boyId] = -1; for(int i = 0; i < n; i ++) if(boysRankings[boyId][i] == girlId){ boysRankings[boyId][i] = -1; return; } } /**************************************** * function description: * Implementation of Gale_Shapley algorithm *****************************************/ void StableMatch(const int n) { InitStatus(n); while(true) { bool flag = false; bool endOfFor = false; // guarantee all the boys have a partner. for(int i = 0; i < n; i ++){ if(boysPartner[i] == -1 || girlsPartner[i] == -1) { flag = true; break; } } if(!flag) break; // for boy who have no partner. for(int i = 0; i < n; i ++) { if(boysPartner[i] == -1){ for(int j = 0; j < n; j ++){ // Since in the list of preference, j had rejected before. if(boysRankings[i][j] == -1) continue; // if j have no partner, then accept. if(girlsPartner[boysRankings[i][j]] == -1){ boysPartner[i] = boysRankings[i][j]; girlsPartner[boysRankings[i][j]] = i; endOfFor = true; break; } else{ // judge whether match is stable or not int useId = GetId(girlsPartner[boysRankings[i][j]], boysRankings[i][j], n); int curId = GetId(i, boysRankings[i][j], n); // if not stable if(curId < useId){ // girl's partner's list, set -1 to mean the girl have rejected. SetStatus(girlsPartner[boysRankings[i][j]], boysRankings[i][j], n); boysPartner[i] = boysRankings[i][j]; girlsPartner[boysRankings[i][j]] = i; endOfFor = true; break; } } } } // find a partner, break out of the loop. if(endOfFor) break; } } } /**************************************** * function description: * print out result. *****************************************/ void Print(const int n) { freopen("result.txt", "w", stdout); cout << "The Matching Results are follows:" << endl; for(int i = 0; i < n; i ++){ cout << boyName[i] << "--" << girlName[boysPartner[i]] << " " << endl; } } /**************************************** * function description: * Main function *****************************************/ int main() { int n = 0; // let every boy and girl have it's own identity. // and get integer ranking array list. SerialNumber(n); // get rankings.S GetRankings(n); // Stable match StableMatch(n); // Print solution Print(n); return 0; }