晚餐客人安排

时间:2014-10-13 19:53:54

标签: python

这是一个家庭作业问题,但我已经研究了一段时间,我不明白我做错了什么。任何帮助将不胜感激。

  

根据以下规则计算N晚餐客人可以围绕圆桌安排自己的方式:

     

最初,所有客人都坐在圆桌旁,没有空座位。为了鼓励对话,主持人要求每位客人站起来,然后坐在三把椅子中的一把:原来的椅子,一个在左边,一个在右边。

     

所有客人都必须坐下。

     

有多少种不同的晚餐客人安排?

     

如果任何客人的主席号码因一种安排而异,则两种安排不同。

     

ABCD与DABC不同。但是,没有人可以移动超过两个地方,   I.E BCAD将无效,因为A移动了两个位置。

     

部分解决方案是:

3 guests can sit in  6 different ways

4 guests can sit in  9 different ways

5 guests can sit in  13 different ways

6 guests can sit in  20 different ways

7 guests can sit in 31 different ways

我的代码最多可容纳5位客人,但对于6位客人,我有19种不同的安排。 7位客人,我有28个安排。我猜我的逻辑有些东西,但我无法理解。

这是我的代码:

def dinner_party_arrangements(N):
    import itertools
    if N > 10:
        return('This function is not built for N > 10.')
    else:
        import math
        result=math.factorial(N)
        baseL=[]
        main=list(range(N))
        L=list(range(N+1))
        L.remove(0)
        combos=(list(itertools.permutations(L)))
        for stuff in combos:
            baseL.append(stuff)
        for guests in baseL:
            resultL=list(guests)
            #looks at single tuple
            for num in main:
                a=num
                b=num+1
                c=num+2
                if resultL[num] == a or resultL[num] == b or resultL[num] == c:
                    pass
                else:
                    result=(result-1)
                    break
        if N<3:
            return(result)
        else:
            return(result+N)

3 个答案:

答案 0 :(得分:1)

以下是您的代码的重构版本,以便更好地理解:

import itertools
import math

def dinner_party_arrangements(N):
    assert N <= 10, 'This function is not built for N > 10.'
    result = math.factorial(N)
    if N < 3:
        return result
    for guests in itertools.permutations(range(1, N+1)):
        for num in range(N):
            if guests[num] not in (num, num+1, num+2):
                result -= 1
                break
    return result+N

我认为问题在于你没有管理&#34; edge&#34;,即位置0可以被客人1(没有改变),客人2,(右邻居)或客人N占用(最后一个,左边的邻居)。桌面上的最后一个位置也是如此。因此,以下方法可行(将import放在一边):

def dinner_party_arrangements(N):
    assert N <= 10, 'This function is not built for N > 10.'
    if N < 3:
        return math.factorial(N)
    allguests = list(itertools.permutations(range(1,N+1)))
    result = len(allguests)
    for guests in allguests:
        for num in range(N):
            if guests[num] not in (N if num==0 else num, num+1, 1 if num==N-1 else num+2):
                result -= 1
                break
    return result

另请注意,我不会在N> 2中使用factorial;我只计算正确的排列数。

更好的是,以下使用了排列函数的惰性:

def dinner_party_arrangements(N):
    assert N <= 10, 'This function is not built for N > 10.'
    if N < 3:
        return math.factorial(N)
    result = 0
    for guests in itertools.permutations(range(1,N+1)):
        for num in range(N):
            if guests[num] not in (N if num==0 else num, num+1, 1 if num==N-1 else num+2):
                break
        else:
            result += 1
    return result

最后,这是一个递归解决方案。与你(和其他人)的方法相反,我不会产生每一个排列,然后消除错误的排列;我从头开始创建解决方案。另外,我使用基于0的编号,这对我来说更自然:

def dinner(gst):
    assert gst > 2  # alogorith doesn't work for < 3 people
    res = []        # result, the list of all possible combinations

    def sub(current, pers):
        if pers == gst:         # base case of recursion; no more person to sit
            res.append(current) # found one combo, add it to result
            return              # and stop here
        for offset in (-1, 0, +1):          # for each move (left, stay, right)
            newpos = (pers + offset) % gst  # compute new position
            if current[newpos] is None:     # seat is not yet taken
                newcurrent = current[:]     # create a copy of current (incomplete) combination
                newcurrent[newpos] = pers   # sit person pos at position newpos
                sub(newcurrent, pers + 1)   # and recurse for the other persons

    sub([None]*gst, 0)  # initialize a combi
    return res

然后

for i in range(3, 8):
    combos = dinner(i)
    print(i, "guests can sit in", len(combos), "ways", combos)

产量

3 guests can sit in 6 ways [[1, 2, 0], [2, 1, 0], [0, 1, 2], [0, 2, 1], [1, 0, 2], [2, 0, 1]]
4 guests can sit in 9 ways [[1, 2, 3, 0], [3, 1, 2, 0], [3, 2, 1, 0], [0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [1, 0, 2, 3], [1, 0, 3, 2], [3, 0, 1, 2]]
5 guests can sit in 13 ways [[1, 2, 3, 4, 0], [4, 1, 2, 3, 0], [4, 1, 3, 2, 0], [4, 2, 1, 3, 0], [0, 1, 2, 3, 4], [0, 1, 2, 4, 3], [0, 1, 3, 2, 4], [0, 2, 1, 3, 4], [0, 2, 1, 4, 3], [1, 0, 2, 3, 4], [1, 0, 2, 4, 3], [1, 0, 3, 2, 4], [4, 0, 1, 2, 3]]
6 guests can sit in 20 ways [[1, 2, 3, 4, 5, 0], [5, 1, 2, 3, 4, 0], [5, 1, 2, 4, 3, 0], [5, 1, 3, 2, 4, 0], [5, 2, 1, 3, 4, 0], [5, 2, 1, 4, 3, 0], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 5, 4], [0, 1, 2, 4, 3, 5], [0, 1, 3, 2, 4, 5], [0, 1, 3, 2, 5, 4], [0, 2, 1, 3, 4, 5], [0, 2, 1, 3, 5, 4], [0, 2, 1, 4, 3, 5], [1, 0, 2, 3, 4, 5], [1, 0, 2, 3, 5, 4], [1, 0, 2, 4, 3, 5], [1, 0, 3, 2, 4, 5], [1, 0, 3, 2, 5, 4], [5, 0, 1, 2, 3, 4]]
7 guests can sit in 31 ways [[1, 2, 3, 4, 5, 6, 0], [6, 1, 2, 3, 4, 5, 0], [6, 1, 2, 3, 5, 4, 0], [6, 1, 2, 4, 3, 5, 0], [6, 1, 3, 2, 4, 5, 0], [6, 1, 3, 2, 5, 4, 0], [6, 2, 1, 3, 4, 5, 0], [6, 2, 1, 3, 5, 4, 0], [6, 2, 1, 4, 3, 5, 0], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 6, 5], [0, 1, 2, 3, 5, 4, 6], [0, 1, 2, 4, 3, 5, 6], [0, 1, 2, 4, 3, 6, 5], [0, 1, 3, 2, 4, 5, 6], [0, 1, 3, 2, 4, 6, 5], [0, 1, 3, 2, 5, 4, 6], [0, 2, 1, 3, 4, 5, 6], [0, 2, 1, 3, 4, 6, 5], [0, 2, 1, 3, 5, 4, 6], [0, 2, 1, 4, 3, 5, 6], [0, 2, 1, 4, 3, 6, 5], [1, 0, 2, 3, 4, 5, 6], [1, 0, 2, 3, 4, 6, 5], [1, 0, 2, 3, 5, 4, 6], [1, 0, 2, 4, 3, 5, 6], [1, 0, 2, 4, 3, 6, 5], [1, 0, 3, 2, 4, 5, 6], [1, 0, 3, 2, 4, 6, 5], [1, 0, 3, 2, 5, 4, 6], [6, 0, 1, 2, 3, 4, 5]]

我希望这会有所帮助。

答案 1 :(得分:0)

这是我的方法。对于大n来说,它确实很慢,但它确实有效。

from itertools import permutations

def arrange( n ):
    # First, place all your guests (0 - n) into an array
    positions = range( n )

    arrangements = 0
    # Iterate over every possible arrangement of guests
    for arrangement in permutations( positions ):
        # begin by assuming the iteration is "valid", that is, no guest
        # hopped more than one spot
        is_valid = True
        # Now iterate over all your guests
        for i in range( n ):
            # If the guest moved more than one spot, this permutation is
            # invalid and we can throw it out
            pos_dif = abs( arrangement.index( i ) - positions.index( i ) )
            if pos_dif > 1 and pos_dif != n-1:
                is_valid = False
                break
        # Otherwise, the iteration is valid and we can increment our count
        if is_valid:
            arrangements += 1
    return arrangements

答案 2 :(得分:0)

我的方法类似于上面的帖子:

def mydin(n):
    import itertools
    initial_table = range(n)
    poss_tables = set(itertools.permutations(initial_table))
    validTables = []
    for table in poss_tables:
        if isValid(initial_table,table):
            validTables.append(table)
    print len(validTables)
    return len(validTables)

def isValid(initial_table,arrangement):
    size = initial_table[-1]
    for i in range(len(initial_table)):
        if i == size:
            if arrangement[i] in (initial_table[i-1],initial_table[i],initial_table[0]):
                continue
            else:
                return False
        elif arrangement[i] in [initial_table[i-1],initial_table[i],initial_table[i+1]]:
            continue
        else:
            return False
    return True

for n in range(3,11):
    mydin(n)

对于我的输出我得到了

6
9
13
20
31
49
78
125