Алгоритм быстрого знакомства - PullRequest
11 голосов
/ 09 июня 2009

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

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

Ответы [ 10 ]

11 голосов
/ 09 июня 2009

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

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

6 голосов
/ 10 июня 2009

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

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

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

5 голосов
/ 09 июня 2009

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

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

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

4 голосов
/ 09 июня 2009
3 голосов
/ 09 июня 2009

Возможно, вы захотите взглянуть на комбинаторную теорию проектирования .

2 голосов
/ 12 июня 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

2 голосов
/ 09 июня 2009

Интуитивно, я не думаю, что вы можете сделать лучше, чем идеальный шаффл , но я не могу доказать это до моего кофе.

1 голос
/ 09 июня 2009

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

0 голосов
/ 10 июня 2009

WRT @ Комментарий Неодима, вот страница на соответствующем сайте:

В нем обсуждаются генетические алгоритмы.

0 голосов
/ 10 июня 2009

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

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

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

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

...