Stable Matching (Gale Sharpley Algorithm)

稳定婚配问题: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;
}


你可能感兴趣的:(Algorithm,Gale_Sharpley,Stable_Matching)