Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 桌子座位,使用什么算法?_Algorithm_Language Agnostic_Computer Science - Fatal编程技术网

Algorithm 桌子座位,使用什么算法?

Algorithm 桌子座位,使用什么算法?,algorithm,language-agnostic,computer-science,Algorithm,Language Agnostic,Computer Science,所以我有这个问题,我需要找出什么样的算法可以解决它 给定一组人,并且给定该组中谁不喜欢谁,在圆桌会议上为所有人安排一个座位,以便没有人坐在他们不喜欢的人旁边(如果可能) 我就是不知道该怎么做。基本上我把它画成一个有向图,节点代表一个人,边从不喜欢的人到不喜欢的人。然后,要将节点排列成一个圆,以便相邻的两个节点之间没有边。然而,我找不到解决这类问题的算法。为了让你的陈述更容易一些,假设你“反转”了你的图形,这样当且仅当两位客人可以坐在一起时,两位客人之间就有了边 现在,您要寻找的是一个循环(闭合行

所以我有这个问题,我需要找出什么样的算法可以解决它

给定一组人,并且给定该组中谁不喜欢谁,在圆桌会议上为所有人安排一个座位,以便没有人坐在他们不喜欢的人旁边(如果可能)


我就是不知道该怎么做。基本上我把它画成一个有向图,节点代表一个人,边从不喜欢的人到不喜欢的人。然后,要将节点排列成一个圆,以便相邻的两个节点之间没有边。然而,我找不到解决这类问题的算法。

为了让你的陈述更容易一些,假设你“反转”了你的图形,这样当且仅当两位客人可以坐在一起时,两位客人之间就有了边

现在,您要寻找的是一个循环(闭合行走),该循环恰好包含每个顶点。这叫做哈密顿循环。一般来说,这是NP难的(你的问题也是如此,因为哈密顿循环的任何实例都可以简化为你的问题),但在某些条件下,这更容易


遗传算法(如JasonC提到的)可以解决大多数问题,整数线性规划是一种选择,约束规划也是。

老实说,我会选择某种退火算法。基本上:

  • 从一套规则和初步安排开始
  • 做一个随机的改变,如果有改进就保留它
  • 重复上述步骤,直到找到解决方案。经过一定的迭代次数后放弃
  • 考虑以下内容(Python)。你想做的第一件事就是想出一种方法来衡量一张桌子的成功与否。在这里,我们定义了一个返回错误配对数的函数,其中:

    • 敌人
      :将一个人映射到他们不能坐在旁边的人列表的字典
    • 表格
      :一种座位安排,以表格周围姓名列表的形式排列。第一个和最后一个元素是相邻的座位,因为它是一个圆桌
    我们什么都用这个。我们的目标是0

    def tablePenalty (enemies, table):
        penalty = 0
        for k, name in enumerate(table):
            p = (k + len(table) - 1) % len(table)
            n = (k + 1) % len(table)
            if table[p] in enemies[name]:
                penalty = penalty + 1
            if table[n] in enemies[name]:
                penalty = penalty + 1
        return penalty
    
    现在我们有了它,我们可以实现一个非常简单的搜索,它只是不断地随机交换用户,直到找到满意的东西。这将以姓名列表作为输入,并生成按座位顺序排列的姓名列表作为输出:

    def findGoodSeating1 (names):
        table = names[:]
        while tablePenalty(enemies, table) > 0:
            i, j = random.sample(range(0, len(table)), 2)
            table[i], table[j] = table[j], table[i]
        return table
    
    当然,这不是一个很好的算法。但它有时是有效的。如果找不到解决方案(或者如果你运气不好),它会挂起,并且它可以随机采取非常迂回的路线来达到解决方案。事实上,它基本上与搜索座位安排的所有扰动相同,只是它以随机顺序进行搜索,有时可以重新检查重复的安排。是的,不太好

    因此,我们可以做一个改进:只有在座位安排得到改善的情况下,才能进行交换:

    def findGoodSeating2 (names):
        table = names[:]
        penalty = tablePenalty(enemies, table)
        while penalty > 0:
            newtable = table[:]
            i, j = random.sample(range(0, len(table)), 2)
            newtable[i], newtable[j] = newtable[j], newtable[i]
            newpenalty = tablePenalty(enemies, newtable)
            if newpenalty <= penalty: # Keep improvements.
                table = newtable
                penalty = newpenalty
        return table
    
    由于算法是随机的,我们最终得到3种不同但令人满意的解决方案

    现在有一些关于上述算法的重要说明:

    • 你可以调整阈值之类的,你真的只需要实验
    • 如果没有解决办法,一切都将悬而不决。即使有解决方案,所有这些都有随机花费很长时间的风险,但这种可能性很低,对于真实的数据集,您可能永远不会注意到
    • 阻止它挂起的方法很简单,我并不是为了简洁而实现它的:只需将算法限制在最大迭代次数。如果您这样做:
      • 对于第一个变量,您的结果实际上是随机的
      • 对于第二种变体,您的结果将是迄今为止最好的
      • 对于第三个变体,您可能希望跟踪总体最佳状态,因为在随机洗牌之后,您可能会达到迭代极限,并丢失关于更早期初始状态的信息
    • 这些算法并不理想——它们很简单。对于这个应用程序,它们的性能足够好。这是重要的部分
    • 你可能只想通过,比方说,用随机位置交换坐在敌人旁边的人来进行实验。这可能会提高性能,也可能不会提高性能

    无论如何,这并不是为了证明什么是最好的算法,只是为了给你一些关于如何从更模糊的方法开始的想法。就我个人而言,其中之一就是我的方法,因为虽然你当然可以找到一个基于图形的解决方案(或者甚至是直接搜索——本质上类似于本例中基于约束的搜索——将一个人放在他们旁边,当你碰到一个糟糕的安排时,返回并尝试下一个扰动),如果您这样做,速度肯定会非常快,但这很容易。

    另请参见和。首先想到的是一个模拟退火/遗传算法,这也是大家的共识(即使是最基本的算法:从随机安排开始,交换两个随机的人-交换是否有所改善?如果是这样,保持不变,不要这样做。重复,直到满意为止),或者如果你的客人名单足够小,可以在合理的时间内完成,通过所有唯一的组合进行简单的暴力搜索。@JasonC不,这是一个不同的问题。婚礼桌的问题要求对客人进行分区,而在这里,你要找的是单桌座位。对我来说,所有这些方法都在随机搜索和退火方法之间。遗传算法不仅应该基于重组,还应该基于种群。所以你会有一个群体,比如说,50个解决方案,通过1)组合(交叉)和2)交换(变异)创造200个后代,然后选择最好的50个来形成你的新群体。遗传算法框架中有自由度,但如果没有解决方案和选择的组合,它就不是遗传算法。@BastianJ我改变了这个词。这是一个粗心的错误。不用担心,我只是想让OP知道GA可能更复杂一点,但也值得一看
    def findGoodSeating3 (names):
        table = names[:]
        penalty = tablePenalty(enemies, table)
        stuck = 0
        while penalty > 0:
            newtable = table[:]
            i, j = random.sample(range(0, len(table)), 2)
            newtable[i], newtable[j] = newtable[j], newtable[i]
            newpenalty = tablePenalty(enemies, newtable)
            stuck = stuck + 1
            if newpenalty < penalty:
                table = newtable
                penalty = newpenalty
                stuck = 0
            elif stuck > 50: # An arbitrary threshold.
                random.shuffle(table)
                penalty = tablePenalty(enemies, table)
                stuck = 0
        return table
    
    import random;
    
    # A list of names to test with.
    names = [ 'Clarke', 'Octavia', 'Bellamy', 'Jaha', 'Murphy', 'Finn',
              'Abby', 'Alie', 'Lexa', 'Kane', 'Lincoln' ]
    
    # Build list of people each person can't sit next to.
    enemies = {}
    for name in names:
        choices = [ x for x in names if x != name ]
        enemies[name] = random.sample(choices, 3) # 3 enemies per person
        print "%s: %s" % (name, enemies[name])
    
    #-------------------------------------------------------------------
    
    def tablePenalty (enemies, table):
        penalty = 0
        for k, name in enumerate(table):
            p = (k + len(table) - 1) % len(table)
            n = (k + 1) % len(table)
            if table[p] in enemies[name]:
                penalty = penalty + 1
            if table[n] in enemies[name]:
                penalty = penalty + 1
        return penalty
    
    def findGoodSeating1 (names):
        table = names[:]
        while tablePenalty(enemies, table) > 0:
            i, j = random.sample(range(0, len(table)), 2)
            table[i], table[j] = table[j], table[i]
        return table
    
    def findGoodSeating2 (names):
        table = names[:]
        penalty = tablePenalty(enemies, table)
        while penalty > 0:
            newtable = table[:]
            i, j = random.sample(range(0, len(table)), 2)
            newtable[i], newtable[j] = newtable[j], newtable[i]
            newpenalty = tablePenalty(enemies, newtable)
            if newpenalty <= penalty:
                table = newtable
                penalty = newpenalty
        return table
    
    def findGoodSeating3 (names):
        table = names[:]
        penalty = tablePenalty(enemies, table)
        stuck = 0
        while penalty > 0:
            newtable = table[:]
            i, j = random.sample(range(0, len(table)), 2)
            newtable[i], newtable[j] = newtable[j], newtable[i]
            newpenalty = tablePenalty(enemies, newtable)
            stuck = stuck + 1
            if newpenalty < penalty:
                table = newtable
                penalty = newpenalty
                stuck = 0
            elif stuck > 3 * len(table):
                random.shuffle(table)
                penalty = tablePenalty(enemies, table)
                stuck = 0
        return table
    
    # Test them:    
    print findGoodSeating1(names)
    print findGoodSeating2(names)
    print findGoodSeating3(names)
    
    Clarke: ['Bellamy', 'Lincoln', 'Octavia']
    Octavia: ['Jaha', 'Abby', 'Bellamy']
    Bellamy: ['Clarke', 'Abby', 'Alie']
    Jaha: ['Finn', 'Lincoln', 'Alie']
    Murphy: ['Octavia', 'Jaha', 'Lexa']
    Finn: ['Lexa', 'Clarke', 'Alie']
    Abby: ['Lexa', 'Clarke', 'Jaha']
    Alie: ['Clarke', 'Kane', 'Lincoln']
    Lexa: ['Murphy', 'Alie', 'Finn']
    Kane: ['Lexa', 'Alie', 'Bellamy']
    Lincoln: ['Murphy', 'Clarke', 'Octavia']
    ['Octavia', 'Lexa', 'Jaha', 'Bellamy', 'Murphy', 'Clarke', 'Kane', 'Finn', 'Lincoln', 'Abby', 'Alie']
    ['Clarke', 'Jaha', 'Bellamy', 'Lexa', 'Octavia', 'Alie', 'Abby', 'Finn', 'Lincoln', 'Kane', 'Murphy']
    ['Murphy', 'Clarke', 'Jaha', 'Lexa', 'Bellamy', 'Lincoln', 'Kane', 'Octavia', 'Finn', 'Abby', 'Alie']