安排数量

时间:2008-12-09 23:41:15

标签: algorithm math

假设我们有 n 元素, a 1 a 2 , ..., a n ,排成一个圆圈。也就是说, a 2 介于 a 1 a 3之间 a 3 介于 a 2 a 4 , a n 介于 a n -1 a 1 ,等等。

每个元素可以取1或0的值。如果有相应的 a i 的值,则两个排列不同不同。例如,当 n = 3时,(1,0,0)和(0,1,0)是不同的排列,即使它们在旋转或反射下可能是同构的。

因为有 n 元素,每个元素都可以取两个值,所以排列的总数是2 n

以下是问题:

可能有多少种安排,这样两个相邻的元素都没有值1?如果有帮助,只考虑 n > 3的情况。

我问这里有几个原因:

  1. 这是在我解决编程问题时出现的
  2. 听起来这个问题可能会受益于布尔逻辑/位算术
  3. 也许没有封闭的解决方案。

4 个答案:

答案 0 :(得分:10)

让我们首先问一个问题“有多少0-1个长度为n的序列,没有两个连续的1?”让答案是A(n)。我们有A(0)= 1(空序列),A(1)= 2(“0”和“1”),A(2)= 3(“00”,“01”和“10”但是不是“11”)。

为了更容易编写重复,我们将A(n)计算为两个数字的总和:
B(n),以0结尾的这种序列的数量,和
C(n),以1结尾的此类序列的数量。

然后B(n)= A(n-1)(取任何长度为n-1的序列,并附加0) 和C(n)= B(n-1)(因为如果在位置n处有1,则在n-1处必须为0。)
这给出A(n)= B(n)+ C(n)= A(n-1)+ B(n-1)= A(n-1)+ A(n-2)。 到现在为止应该很熟悉: - )

A(n)就是Fibonacci数F n + 2 ,其中Fibonacci序列由
F 0 = 0,F 定义1 = 1,F n + 2 = F n + 1 + F n ,n≥0。

现在提出你的问题。我们将分别计算 1 = 0和 1 = 1的排列数。对于前者, 2 ... a n 可以是任何序列(没有连续的1),因此数字是A(n-1)= F n + 1个。对于后者,我们必须有一个 2 = 0,然后一个 3 ... a n 是没有连续1的任何序列以0 结束,即B(n-2)= A(n-3)= F n-1

所以答案是F n + 1 + F n-1

实际上,我们可以比那个答案更进一步。请注意,如果您将答案称为
G(n)= F n + 1 + F n-1 ,则 G(n + 1)= F n + 2 + F n ,和
G(n + 2)= F n + 3 + F n + 1 ,因此即使G(n)也满足与Fibonacci序列相同的复发! [实际上,Fibonacci类序列的任何线性组合都会满足同样的复发,所以并不是那么令人惊讶。]所以计算答案的另一种方法是使用:
G(2)= 3
G(3)= 4
n≥4时G(n)= G(n-1)+ G(n-2)。

现在你也可以使用closed form F n =(α n n )/(α- β)(其中α和β为(1±√5)/ 2,x 2 -x-1 = 0)的根,得到
G(n)=((1 +√5)/ 2) n +((1-√5)/ 2) n
[你可以忽略第二项,因为对于大n,它非常接近0,实际上G(n)是最接近的整数((1 +√5)/ 2) n < / strong>所有n≥2。]

答案 1 :(得分:1)

我决定修改一个小脚本来尝试一下:

#!/usr/bin/python
import sys

# thx google 
bstr_pos = lambda n: n>0 and bstr_pos(n>>1)+str(n&1) or ""

def arrangements(n):
    count = 0
    for v in range(0, pow(2,n)-1):
        bin = bstr_pos(v).rjust(n, '0')
        if not ( bin.find("11")!=-1 or ( bin[0]=='1' and bin[-1]=='1' ) ):
            count += 1
            print bin
    print "Total = " + str(count)

arrangements(int(sys.argv[1]))

为5运行这个,给了我总共11个可能性00000, 00001, 00010, 00100, 00101, 01000, 01001, 01010, 10000, 10010, 10100

P.S。 - 请原谅上面代码中的not()。

答案 2 :(得分:0)

把我天真的脚本扔进混合物中。很多机会可以缓存部分结果,但是对于小n来说它运行得足够快,我没有打扰。

def arcCombinations(n, lastDigitMustBeZero):
    """Takes the length of the remaining arc of the circle, and computes
       the number of legal combinations.
       The last digit may be restricted to 0 (because the first digit is a 1)"""

    if n == 1: 
        if lastDigitMustBeZero:
            return 1 # only legal answer is 0
        else:
            return 2 # could be 1 or 0.
    elif n == 2:
        if lastDigitMustBeZero:
            return 2 # could be 00 or 10
        else:
            return 3 # could be 10, 01 or 00
    else:
        # Could be a 1, in which case next item is a zero.
        return (
            arcCombinations(n-2, lastDigitMustBeZero) # If it starts 10
            + arcCombinations(n-1, lastDigitMustBeZero) # If it starts 0
            )

def circleCombinations(n):
    """Computes the number of legal combinations for a given circle size."""

    # Handle case where it starts with 0 or with 1.
    total = (
            arcCombinations(n-1,True) # Number of combinations where first digit is a 1.
            +
            arcCombinations(n-1,False) # Number of combinations where first digit is a 0.
        )
    return total


print circleCombinations(13)

答案 3 :(得分:0)

此问题与Zeckendorf representations非常相似。由于圆度约束,我找不到一种明显的方法来应用Zeckendorf定理,但Fibonacci数在这个问题中显然非常普遍。