БлогNot. Задача о марьяже (о стабильных браках)

Задача о марьяже (о стабильных браках)

Как контейнеры не делают наш код легче и понятней :)

Постановка задачи есть в "Вики", там же - решение на классическом Си. Наше решение получилось несколько более громоздким, зато на стандартных контейнерах STL и с именами вместо индексов.

Предполагается, что мощности множеств одинаковы, то есть, пары можно образовать в любом случае, корректность заполнения исходных данных men_data и women_data не контролируется. Зато код в таком виде должен нормально обобщаться на неравное количество партнёров, думается.

Консольное приложение C++ проверялось в актуальной сборке Visual Studio 2019, далее приводится полный листинг и копия вывода в консоль.

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>

typedef std::vector<std::string> PrefList;
typedef std::map<std::string, PrefList> PrefMap;
typedef std::map<std::string, std::string> Couples;

bool prefers(const PrefList& prefer, const std::string& first, const std::string& second) {
 // Появляется ли «первый» перед «вторым» в списке предпочтений?
 for (PrefList::const_iterator it = prefer.begin(); it != prefer.end(); ++it) {
  if (*it == first) return true;
  if (*it == second) return false;
 }
 return false;
}

void check_stability(const Couples& engaged, const PrefMap& men_pref, const PrefMap& women_pref) {
 std::cout << "Stablility:" << std::endl;
 bool stable = true;
 for (Couples::const_iterator it = engaged.begin(); it != engaged.end(); ++it) {
  const std::string& bride = it->first;
  const std::string& groom = it->second;
  const PrefList& preflist = men_pref.at(groom);
  for (PrefList::const_iterator it = preflist.begin(); it != preflist.end(); ++it) {
   if (*it == bride) break; // он предпочитает свою невесту
   if (prefers(preflist, *it, bride) && // он предпочитает другую женщину
    prefers(women_pref.at(*it), groom, engaged.at(*it))) { // другая женщина предпочитает его
    std::cout << "\t" << *it <<
     " prefers " << groom <<
     " over " << engaged.at(*it) <<
     " and " << groom <<
     " prefers " << *it <<
     " over " << bride << std::endl;
    stable = false;
   }
  }
 }
 if (stable) std::cout << "\t(all marriages stable)" << std::endl;
}

//Исходные данные
const int N = 5;
const char* men_data[][N + 1] = {
 { "Corwin", "Basya","Avka","Delta","Murka","Fifi" },
 { "Dunduk", "Delta","Basya","Avka","Fifi","Murka" },
 { "Tema",   "Avka","Basya","Fifi","Murka","Delta" },
 { "Baran",  "Fifi","Delta","Murka","Basya","Avka" },
 { "Sidor",  "Basya","Fifi","Delta","Murka","Avka" }
};

const char* women_data[][N + 1] = {
 { "Avka", "Dunduk","Corwin","Baran","Sidor","Tema" },
 { "Basya", "Corwin","Dunduk","Sidor","Baran","Tema" },
 { "Delta", "Tema","Baran","Sidor","Dunduk","Corwin" },
 { "Fifi", "Sidor","Dunduk","Corwin","Tema","Baran" },
 { "Murka", "Baran","Tema","Corwin","Sidor","Dunduk" }
};

int main() {
 PrefMap men_pref, women_pref;
 std::queue<std::string> bachelors;
 for (int i = 0; i < N; ++i) { // люди
  for (int j = 1; j < N + 1; ++j) { // предпочтения
   men_pref[men_data[i][0]].push_back(men_data[i][j]);
   women_pref[women_data[i][0]].push_back(women_data[i][j]);
  }
  bachelors.push(men_data[i][0]);
 }
 Couples engaged; // <Ж,М>
 std::cout << "Tests:" << std::endl;
 while (!bachelors.empty()) {
  const std::string& suitor = bachelors.front();
  const PrefList& preflist = men_pref[suitor];
  for (PrefList::const_iterator it = preflist.begin(); it != preflist.end(); ++it) {
   const std::string& bride = *it;
   if (engaged.find(bride) == engaged.end()) { // она доступна
    std::cout << "\t" << bride << " & " << suitor << std::endl;
    engaged[bride] = suitor; // соединить
    break;
   }
   const std::string& groom = engaged[bride];
   if (prefers(women_pref[bride], suitor, groom)) {
    std::cout << "\t" << bride << " poslala " << groom << " radi " << suitor << std::endl;
    bachelors.push(groom); // сбросить этот вариант
    engaged[bride] = suitor; 
    break;
   }
  }
  bachelors.pop();
 }
 std::cout << "Couples:" << std::endl;
 for (Couples::const_iterator it = engaged.begin(); it != engaged.end(); ++it) {
  std::cout << "\t" << it->first << " & " << it->second << std::endl;
 }
 check_stability(engaged, men_pref, women_pref);

 //Две дуры поменялись мужиками:
 std::cout << "Perturbation:" << std::endl;
 std::swap(engaged["Avka"], engaged["Basya"]);
 std::cout << "\tengage Avka with " << engaged["Avka"] << " and Basya with " << engaged["Basya"] << std::endl;
 check_stability(engaged, men_pref, women_pref);
 return 0;
}
Tests:
        Basya & Corwin
        Delta & Dunduk
        Avka & Tema
        Fifi & Baran
        Fifi poslala Baran radi Sidor
        Delta poslala Dunduk radi Baran
        Avka poslala Tema radi Dunduk
        Murka & Tema
Couples:
        Avka & Dunduk
        Basya & Corwin
        Delta & Baran
        Fifi & Sidor
        Murka & Tema
Stablility:
        (all marriages stable)
Perturbation:
        engage Avka with Corwin and Basya with Dunduk
Stablility:
        Basya prefers Corwin over Dunduk and Corwin prefers Basya over Avka

13.06.2022, 23:37 [743 просмотра]


теги: c++ алгоритм

К этой статье пока нет комментариев, Ваш будет первым