Speed dating algorithm

后端 未结 9 623
深忆病人
深忆病人 2021-02-04 10:19

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

相关标签:
9条回答
  • 2021-02-04 10:30

    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

    0 讨论(0)
  • 2021-02-04 10:36

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

    0 讨论(0)
  • 2021-02-04 10:36

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

    0 讨论(0)
  • 2021-02-04 10:37

    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.

    0 讨论(0)
  • 2021-02-04 10:41

    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

    0 讨论(0)
  • 2021-02-04 10:43

    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...

    0 讨论(0)
提交回复
热议问题