Алгоритм быстрых свиданий

Я работаю в консалтинговой организации и большую часть времени бываю у клиентов. Из-за этого я редко встречаюсь со своими коллегами. Чтобы лучше узнать друг друга, мы собираемся устроить званый ужин. Там будет много маленьких столиков, чтобы люди могли поболтать. Чтобы поговорить с как можно большим количеством разных людей во время вечеринки, все должны меняться столами с некоторым интервалом, скажем, каждый час.

Как написать программу, создающую расписание переключения столов? Просто чтобы дать вам некоторые цифры; в этом случае будет около 40 человек, и за каждым столом может находиться не более 8 человек. Но алгоритм, конечно, должен быть универсальным.


person Hallis    schedule 09.06.2009    source источник
comment
Должно ли быть равное количество мужчин и женщин за столом?   -  person Unknown    schedule 09.06.2009
comment
Нет, я думаю, что проблема и так достаточно сложна.   -  person Hallis    schedule 09.06.2009
comment
Почему бы вам просто не создать группу в Facebook, чтобы поддерживать связь друг с другом?   -  person Daniel Daranas    schedule 09.06.2009
comment
После прочтения части часто задаваемых вопросов о домашнем задании, в которой говорится, что тег «Домашнее задание» не следует добавлять без доказательства того, что это домашнее задание, я решил удалить тег до тех пор, пока ОП не заявит, что это вопрос домашнего задания (примечание: не большинство студенты сейчас на летних каникулах?). Обсуждать.   -  person Mike B    schedule 10.06.2009
comment
Доказано, что это NP сложно. Конкретный случай размера стола 2 и я хочу, чтобы все встретились со всеми, в просторечии известен как проблема гомосексуальных быстрых свиданий. Не существует оптимального и быстрого решения.   -  person Jon Watte    schedule 08.06.2019
comment
@JonWatte, конкретный экземпляр размера стола 2, и я хочу, чтобы все встретились со всеми, также известен как турнир по круговой системе. Это легко решить: en.wikipedia.org/wiki/.   -  person Hugh W    schedule 26.05.2020


Ответы (9)


Это звучит как приложение для генетического алгоритма:

  1. Выберите случайную перестановку 40 гостей - это одна рассадка.
  2. Повторите случайную перестановку N раз (n – сколько раз вы должны поменяться местами за ночь)
  3. Соедините перестановки вместе - это хромосома для одного организма
  4. Повторяйте, сколько организмов вы хотите вывести в одном поколении.
  5. Показатель пригодности — это количество людей, которых каждый человек видел за одну ночь (или, наоборот, обратное количество людей, которых он не видел)
  6. Размножайте, мутируйте и вводите новые организмы, используя обычный метод, и повторяйте, пока не получите удовлетворительный ответ.

Вы можете добавить любые другие факторы, которые вам нравятся, в фитнес, такие как соотношение мужчин и женщин и т. д., не меняя существенно основной метод.

person 1800 INFORMATION    schedule 09.06.2009
comment
Если я ошибаюсь, укажите, почему вместо молчаливого голосования, спасибо - person 1800 INFORMATION; 09.06.2009
comment
Вы не должны без разбора бросать генетические алгоритмы на любую возникающую проблему оптимизации, особенно на мелкие и регулярные проблемы, подобные этой. - person starblue; 09.06.2009
comment
Здесь есть много хороших предложений, но в итоге я реализовал это как генетический алгоритм. Главным образом потому, что я никогда раньше не делал GA, и это звучало весело. Вы можете скачать мой код здесь: hallvardkorsgaard.spaces.live.com/ блог/ - person Hallis; 21.06.2009

вот идея
первая работа с точки зрения первого человека .. назовем его X
X должен встретиться со всеми другими людьми в комнате, поэтому мы должны разделить оставшихся людей на n групп (где n = #_of_people/capacity_per_table ) и заставить его сидеть с одной из этих групп за итерацию
Теперь, когда о X позаботились, мы рассмотрим следующего человека Y
WLOG Y будет человеком, с которым X должен был сидеть в сама первая итерация.. так что мы уже знаем группу таблицы Y для этого периода времени.. мы должны затем разделить оставшихся людей на группы так, чтобы каждая группа сидела с Y для каждой последовательной итерации.. и для каждой итерации группа X и группа Y не иметь общего человека
.. Я думаю, если вы будете продолжать делать что-то подобное, вы получите оптимальное решение (если оно существует)

В качестве альтернативы вы можете решить проблему с помощью краудсорсинга, дав каждому человеку карточку, на которой он мог бы написать имена всех людей, с которыми он обедал... и в конце мероприятия вручить какой-то приз человеку с наибольшим количеством имен в списке. их карта

person Aditya Mukherji    schedule 09.06.2009
comment
Нравится твоя идея с картами! Генетическое программирование в действии. :) - person Alexander Prokofyev; 09.06.2009
comment
Если есть около 40 человек и есть только один приз, большинство людей не будут пытаться получить приз - они просто останутся со знакомыми. - person Nosredna; 10.06.2009

Почему бы не подражать реальному миру?

class Person { 
    void doPeriodically() {
         do {
             newTable = random (numberOfTables);
         } while (tableBusy(newTable))
         switchTable (newTable) 
    }
}

Да, и обратите внимание, что существует аналогичный алгоритм поиска партнера для спаривания, и, по слухам, он эффективен для тех 99% людей, которые не тратят все свое свободное время на ответы на вопросы по программированию...

person ilya n.    schedule 09.06.2009

План идеального стола

person user79755    schedule 09.06.2009
comment
Я автор PerfectTablePlan. PerfectTablePlan может справиться с этим сценарием, но требует некоторого ручного вмешательства: perfecttableplan .com/html/PerfectTablePlan_Windows_Help_402/ В моем «списке пожеланий» есть расширение PerfectTablePlan для лучшей обработки нескольких мест. - person Andy Brice; 10.06.2009
comment
@Энди Брайс - Хе-хе, я просто в шутку написал комментарий. - person user79755; 11.06.2009
comment
Обновлять. PerfectTablePlan Professional edition v5 может обрабатывать несколько рабочих мест за одну операцию (используя генетический алгоритм). Он также может справляться с дополнительными ограничениями, такими как удержание пар вместе на всех местах или попытка сесть А рядом с Б только на 1 место. См.: perfecttableplan.com/help/52/windows/html/ - person Andy Brice; 19.02.2015

Вы можете ознакомиться с теорией комбинаторного дизайна.

person starblue    schedule 09.06.2009

Интуитивно я не думаю, что вы можете сделать лучше, чем идеальное перемешивание, но это выходит за рамки моих предварительных -кофе познание, чтобы доказать это.

person user60401    schedule 09.06.2009

Это было очень смешно! :D

Я пробовал другой метод, но логика, предложенная adi92 (карта + приз), работает лучше, чем любая другая, которую я пробовал.

Это работает следующим образом:

  1. приходит парень и осматривает все столы
  2. для каждого стола со свободными местами он подсчитывает, сколько людей ему еще предстоит встретить, затем выбирает тот, где больше незнакомых людей
  3. если за двумя столами одинаковое количество незнакомых людей, то парень выберет тот, где больше свободных мест, чтобы было больше шансов встретить больше новых людей

на каждом шагу порядок людей, занимающих места, является случайным (это позволяет избежать возможных бесконечных циклов), это «демонстрация» рабочего алгоритма в python:

import random

class Person(object):

    def __init__(self, name):
        self.name = name
        self.known_people = dict()

    def meets(self, a_guy, propagation = True):
        "self meets a_guy, and a_guy meets self"
        if a_guy not in self.known_people:
            self.known_people[a_guy] = 1
        else:
            self.known_people[a_guy] += 1

        if propagation: a_guy.meets(self, False)

    def points(self, table):
        "Calculates how many new guys self will meet at table"
        return len([p for p in table if p not in self.known_people])

    def chooses(self, tables, n_seats):
        "Calculate what is the best table to sit at, and return it"
        points = 0
        free_seats = 0
        ret = random.choice([t for t in tables if len(t)<n_seats])

        for table in tables:
            tmp_p = self.points(table)
            tmp_s = n_seats - len(table)
            if tmp_s == 0: continue
            if tmp_p > points or (tmp_p == points and tmp_s > free_seats):
                ret = table
                points = tmp_p
                free_seats = tmp_s

        return ret

    def __str__(self):
        return self.name
    def __repr__(self):
        return self.name


def Switcher(n_seats, people):
    """calculate how many tables and what switches you need
        assuming each table has n_seats seats"""

    n_people = len(people)
    n_tables = n_people/n_seats

    switches = []
    while not all(len(g.known_people) == n_people-1 for g in people):
        tables = [[] for t in xrange(n_tables)]

        random.shuffle(people) # need to change "starter"

        for the_guy in people:
            table = the_guy.chooses(tables, n_seats)
            tables.remove(table)
            for guy in table:
                the_guy.meets(guy)
            table += [the_guy]
            tables += [table]

        switches += [tables]

    return switches



lst_people = [Person('Hallis'),
      Person('adi92'),
      Person('ilya n.'),
      Person('m_oLogin'),
      Person('Andrea'),
      Person('1800 INFORMATION'),
      Person('starblue'),
      Person('regularfry')]    



s = Switcher(4, lst_people)

print "You need %d tables and %d turns" % (len(s[0]), len(s))
turn = 1
for tables in s:
    print 'Turn #%d' % turn
    turn += 1
    tbl = 1
    for table in tables:
        print '  Table #%d - '%tbl, table
        tbl += 1
    print '\n'

Это выведет что-то вроде:

You need 2 tables and 3 turns
Turn #1
  Table #1 -  [1800 INFORMATION, Hallis, m_oLogin, Andrea]
  Table #2 -  [adi92, starblue, ilya n., regularfry]


Turn #2
  Table #1 -  [regularfry, starblue, Hallis, m_oLogin]
  Table #2 -  [adi92, 1800 INFORMATION, Andrea, ilya n.]


Turn #3
  Table #1 -  [m_oLogin, Hallis, adi92, ilya n.]
  Table #2 -  [Andrea, regularfry, starblue, 1800 INFORMATION]

Из-за случайности это не всегда будет происходить с минимальным количеством переключений, особенно с большими группами людей. Затем вы должны запустить его пару раз и получить результат с меньшим количеством ходов (так что вы не напрягаете всех людей на вечеринке :P), и это легко кодировать :P

PS: Да, вы можете сэкономить призовые :P

person Andrea Ambu    schedule 11.06.2009

Вы также можете взглянуть на стабильную задачу соответствия. Решение этой проблемы предполагает использование алгоритма максимального потока. http://en.wikipedia.org/wiki/Stable_marriage_problem

person user120015    schedule 09.06.2009

Я бы не стал заморачиваться с генетическими алгоритмами. Вместо этого я бы сделал следующее, что представляет собой небольшое усовершенствование повторяющихся идеальных тасовок.

Пока (есть два человека, которые не встречались):

  1. Рассмотрим граф, в котором каждый узел является гостем, а ребро (A, B) существует, если A и B НЕ сидели за одним и тем же столом. Найдите все соединенные компоненты этого графика. Если есть какие-либо связанные компоненты размером ‹ tablesize, запланируйте эти связанные компоненты на таблицах. Обратите внимание, что даже это на самом деле является примером сложной проблемы, известной как упаковка в контейнеры, но уменьшение первого соответствия, вероятно, будет подходящим, что может быть достигнуто путем сортировки связанных компонентов в порядке от наибольшего к наименьшему, а затем помещая их каждый из них в очередь за первым столом, где они подходят.
  2. Выполните случайную перестановку оставшихся элементов. (Другими словами, рассадите оставшихся людей случайным образом, сначала это будут все.)
  3. Счетчик приращений, указывающий количество раундов.

Повторяйте описанное выше некоторое время, пока количество раундов не сойдется.

person Martin Hock    schedule 10.06.2009