views:

980

answers:

11

I work in a consulting organization and am most of the time at customer locations. Because of that I rarely meet my colleagues. To get to know each other better we are going to arrange a dinner party. There will be many small tables so people can have a chat. In order to talk to as many different people as possible during the party, everybody has to switch tables at some interval, say every hour.

How do I write a program that creates the table switching schedule? Just to give you some numbers; in this case there will be around 40 people and there can be at most 8 people at each table. But, the algorithm needs to be generic of course

+11  A: 

So... What have you come up with so far? :)

m_oLogin
I'm just curious, why do you think its homework? (not saying it isn't)
Unknown
because the author has the Student badge. :) no, seriously, I posted this answer seeing it had the homework tag. it has been removed since. it's just too bad the author shows no sign of trying to find a solution himself. it just looks like a homework problem statement...
m_oLogin
But it is a very interesting problem! :D
Andrea Ambu
Because conceptually interesting, bereft of real-world "dirty" details, and completely impractical (this dinner would take days), yet the author seems completely unaware of this naive juxstaposition. That is one of the surest footprints of a "re-presented" homework problem.
RBarryYoung
+11  A: 

heres an idea
first work from the perspective of the first person .. lets call him X
X has to meet all the other people in the room, so we should divide the remaining people into n groups ( where n = #_of_people/capacity_per_table ) and make him sit with one of these groups per iteration
Now that X has been taken care of, we will consider the next person Y
WLOG Y be a person X had to sit with in the first iteration itself.. so we already know Y's table group for that time-frame.. we should then divide the remaining people into groups such that each group sits with Y for every consecutive iteration.. and for each iteration X's group and Y's group have no person in common
.. I guess, if you keep doing something like this, you will get an optimal solution (if one exists)

Alternatively you could crowd source the problem by giving each person a card where they could write down the names of all the people they got dine with.. and at the end of event, present some kind of prize to the person with the most names in their card

adi92
+1 to alternative suggestion
tanascius
Like your idea about cards! Genetic programming in action. :)
Alexander Prokofyev
Reminds me http://en.wikipedia.org/wiki/Dance_card
mouviciel
If there are around 40 people and there's only one prize, most people won't try for the prize--they'll just stay with people they know.
Nosredna
+3  A: 

This sounds like an application for genetic algorithm:

  1. Select a random permutation of the 40 guests - this is one seating arrangement
  2. Repeat the random permutation N time (n is how many times you are to switch seats in the night)
  3. Combine the permutations together - this is the chromosome for one organism
  4. Repeat for how ever many organisms you want to breed in one generation
  5. The fitness score is the number of people each person got to see in one night (or alternatively - the inverse of the number of people they did not see)
  6. Breed, mutate and introduce new organisms using the normal method and repeat until you get a satisfactory answer

You can add in any other factors you like into the fitness, such as male/female ratio and so on without greatly changing the underlying method.

1800 INFORMATION
If I'm wrong, please point out why instead of the silent down-vote thing, thanks
1800 INFORMATION
You shouldn't indiscriminately throw genetic algorithms at any optimization problem that comes along, in particular not at small and regular problems like this.
starblue
There are many good suggestions here, but I ended up implementing this as a genetic algorithm. Mainly because I hadn't done any GA's before and it sounded fun to do. You can download my code from here: http://hallvardkorsgaard.spaces.live.com/blog/cns!6A4336898CA0055D!407.entry
Hallis
+2  A: 

You might want to have a look at combinatorial design theory.

starblue
+2  A: 

Intuitively I don't think you can do better than a perfect shuffle, but it's beyond my pre-coffee cognition to prove it.

+1  A: 

You can also take look at stable matching problem. The solution to this problem involves using max-flow algorithm. http://en.wikipedia.org/wiki/Stable_marriage_problem

+3  A: 

Perfect Table Plan

I am the author of PerfectTablePlan. PerfectTablePlan can handle this scenario, but it needs a bit of manual intervention:http://www.perfecttableplan.com/html/PerfectTablePlan_Windows_Help_402/index.html?arrange_multiple_seatings_for_an_event.htmIt is on my 'wishlist' to extend PerfectTablePlan to handle multiple seatings better.
Andy Brice
@Andy Brice: Nice program!
Alexander Prokofyev
@Andy Brice - Hehe, I just made the comment in jest.
+5  A: 

Why not imitate real world?

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

Oh, and note that there is a similar algorithm for finding a mating partner and it's rumored to be effective for those 99% of people who don't spend all of their free time answering programming questions...

ilya n.
I'm glad to see that my speed dating algorithm has some success on this forum...
ilya n.
A: 

I wouldn't bother with genetic algorithms. Instead, I would do the following, which is a slight refinement on repeated perfect shuffles.

While (there are two people who haven't met):

  1. Consider the graph where each node is a guest and edge (A, B) exists if A and B have NOT sat at the same table. Find all the connected components of this graph. If there are any connected components of size < tablesize, schedule those connected components at tables. Note that even this is actually an instance of a hard problem known as Bin packing, but first fit decreasing will probably be fine, which can be accomplished by sorting the connected components in order of biggest to smallest, and then putting them each of them in turn at the first table where they fit.
  2. Perform a random permutation of the remaining elements. (In other words, seat the remaining people randomly, which at first will be everyone.)
  3. Increment counter indicating number of rounds.

Repeat the above for a while until the number of rounds seems to converge.

Martin Hock
A: 

WRT @Neodymium's comment, here's a page on the site that is relevant:

It discusses genetic algorithms.

+1  A: 

This one was very funny! :D

I tried different method but the logic suggested by adi92 (card + prize) is the one that works better than any other I tried.

It works like this:

  1. a guy arrives and examines all the tables
  2. for each table with free seats he counts how many people he has to meet yet, then choose the one with more unknown people
  3. if two tables have an equal number of unknown people then the guy will choose the one with more free seats, so that there is more probability to meet more new people

at each turn the order of the people taking seats is random (this avoid possible infinite loops), this is a "demo" of the working algorithm in 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'

This will output something like:

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]

Because of the random it won't always come with the minimum number of switch, especially with larger sets of people. You should then run it a couple of times and get the result with less turns (so you do not stress all the people at the party :P ), and it is an easy thing to code :P

PS: Yes, you can save the prize money :P

Andrea Ambu