Python 一般酒吧及明星

Python 一般酒吧及明星,python,algorithm,Python,Algorithm,我有一个用Python实现的算法,它将一个和的所有分解输出到3个容器中,用于从0到5的和。 我想概括一下我的代码,这样它就可以使用N个箱子(其中N小于最大和,即这里的5)。 模式是,如果有3个容器,则需要2个嵌套循环;如果有N个容器,则需要N-1个嵌套循环 有人能想出一种通用的方法来写这个,可能不使用循环 # bars and stars algorithm N=5 for n in range(0,N): x=[1]*n for i in range(0,(len(x)+1))

我有一个用Python实现的算法,它将一个和的所有分解输出到3个容器中,用于从0到5的和。 我想概括一下我的代码,这样它就可以使用N个箱子(其中N小于最大和,即这里的5)。 模式是,如果有3个容器,则需要2个嵌套循环;如果有N个容器,则需要N-1个嵌套循环

有人能想出一种通用的方法来写这个,可能不使用循环

# bars and stars algorithm
N=5
for n in range(0,N):
    x=[1]*n
    for i in range(0,(len(x)+1)):
        for j in range(i,(len(x)+1)):
            print sum(x[0:i]), sum(x[i:j]), sum(x[j:len(x)])

这可以通过以下方法递归解决:

#n bins, k stars,
def F(n,k):
  #n bins, k stars, list holds how many elements in current assignment
  def aux(n,k,list):
        if n == 0: #stop clause
            print list
        elif n==1: #making sure all stars are distributed
            list[0] = k
            aux(0,0,list)
        else: #"regular" recursion:
            for i in range(k+1):
                #the last bin has i stars, set them and recurse
                list[n-1] = i
                aux(n-1,k-i,list)
  aux(n,k,[0]*n)
我们的想法是“猜测”最后一个箱子里有多少颗星星,分配它们,然后递归到一个更小的问题,即更少的星星(分配的数量)和一个更少的箱子


注意:更换管路很容易

print list

设置每个箱子中的星号时,可以使用您想要的任何输出格式。

这可以通过以下方法递归解决:

#n bins, k stars,
def F(n,k):
  #n bins, k stars, list holds how many elements in current assignment
  def aux(n,k,list):
        if n == 0: #stop clause
            print list
        elif n==1: #making sure all stars are distributed
            list[0] = k
            aux(0,0,list)
        else: #"regular" recursion:
            for i in range(k+1):
                #the last bin has i stars, set them and recurse
                list[n-1] = i
                aux(n-1,k-i,list)
  aux(n,k,[0]*n)
我们的想法是“猜测”最后一个箱子里有多少颗星星,分配它们,然后递归到一个更小的问题,即更少的星星(分配的数量)和一个更少的箱子


注意:更换管路很容易

print list

当每个箱子中的星星数设置好时,可以使用您想要的任何输出格式。

一次只执行一步

首先,删除
sum()
调用。我们不需要它们:

N=5
for n in range(0,N):
    x=[1]*n
    for i in range(0,(n+1)):  # len(x) == n
        for j in range(i,(n+1)):
            print i, j - i, n - j
请注意,
x
是一个未使用的变量:

N=5
for n in range(0,N):
    for i in range(0,(n+1)):
        for j in range(i,(n+1)):
            print i, j - i, n - j
是概括的时候了。上面的算法对于
N
星和三个条是正确的,所以我们只需要对这些条进行推广

递归地执行此操作。对于基本情况,我们要么有零条,要么有零星,这两者都是微不足道的。对于递归情况,运行最左侧条的所有可能位置,并在每种情况下递归:

from __future__ import print_function

def bars_and_stars(bars=3, stars=5, _prefix=''):
    if stars == 0:
        print(_prefix + ', '.join('0'*(bars+1)))
        return
    if bars == 0:
        print(_prefix + str(stars))
        return
    for i in range(stars+1):
        bars_and_stars(bars-1, stars-i, '{}{}, '.format(_prefix, i))

为了获得额外积分,我们可以将
range()
更改为
xrange()
,但这只会在您移植到Python 3时给您带来麻烦。

一步一个脚印

首先,删除
sum()
调用。我们不需要它们:

N=5
for n in range(0,N):
    x=[1]*n
    for i in range(0,(n+1)):  # len(x) == n
        for j in range(i,(n+1)):
            print i, j - i, n - j
请注意,
x
是一个未使用的变量:

N=5
for n in range(0,N):
    for i in range(0,(n+1)):
        for j in range(i,(n+1)):
            print i, j - i, n - j
是概括的时候了。上面的算法对于
N
星和三个条是正确的,所以我们只需要对这些条进行推广

递归地执行此操作。对于基本情况,我们要么有零条,要么有零星,这两者都是微不足道的。对于递归情况,运行最左侧条的所有可能位置,并在每种情况下递归:

from __future__ import print_function

def bars_and_stars(bars=3, stars=5, _prefix=''):
    if stars == 0:
        print(_prefix + ', '.join('0'*(bars+1)))
        return
    if bars == 0:
        print(_prefix + str(stars))
        return
    for i in range(stars+1):
        bars_and_stars(bars-1, stars-i, '{}{}, '.format(_prefix, i))

为了获得额外的积分,我们可以将
range()
更改为
xrange()
,但是当您移植到Python 3时,这只会给您带来麻烦。

另一个递归变量,使用生成器函数,也就是说,它不是立即打印结果,而是一个接一个地生成结果,由调用方打印

将循环转换为递归算法的方法如下:

  • 确定“基本情况”:当没有更多条时,只需打印星号即可
  • 对于第一段中的任意数量的星,递归地确定其余部分的可能分区,并将它们组合起来
您还可以将其转化为将任意序列划分为块的算法:

def partition(seq, n, min_size=0):
    if n == 0:
        yield [seq]
    else:
        for i in range(min_size, len(seq) - min_size * n + 1):
            for res in partition(seq[i:], n-1, min_size):
                yield [seq[:i]] + res
用法示例:

for res in partition("*****", 2):
    print "|".join(res)

另一个递归变量使用生成器函数,即,它不是立即打印结果,而是一个接一个地生成结果,供调用方打印

将循环转换为递归算法的方法如下:

  • 确定“基本情况”:当没有更多条时,只需打印星号即可
  • 对于第一段中的任意数量的星,递归地确定其余部分的可能分区,并将它们组合起来
您还可以将其转化为将任意序列划分为块的算法:

def partition(seq, n, min_size=0):
    if n == 0:
        yield [seq]
    else:
        for i in range(min_size, len(seq) - min_size * n + 1):
            for res in partition(seq[i:], n-1, min_size):
                yield [seq[:i]] + res
用法示例:

for res in partition("*****", 2):
    print "|".join(res)

如果这不仅仅是一个学习练习,那么您就没有必要使用自己的算法来生成分区:Python的标准库已经以函数的形式提供了您所需要的大部分内容

根据您链接到的上的定理2,有
n+k-1选择k-1
方法将
n
项划分为
k
存储箱,该定理的证明给出了组合和分区之间的明确对应关系。所以我们所需要的就是(1)生成这些组合的方法,(2)将每个组合转换为相应分区的代码。
itertools.combines
函数已经提供了第一个成分。对于第二种情况,每个组合给出了分隔器的位置;连续分隔器位置之间的差异(减1)给出了分区大小。代码如下:

import itertools

def partitions(n, k):
    for c in itertools.combinations(range(n+k-1), k-1):
        yield [b-a-1 for a, b in zip((-1,)+c, c+(n+k-1,))]

# Example usage
for p in partitions(5, 3):
    print(p)
下面是运行上述代码的输出

[0, 0, 5]
[0, 1, 4]
[0, 2, 3]
[0, 3, 2]
[0, 4, 1]
[0, 5, 0]
[1, 0, 4]
[1, 1, 3]
[1, 2, 2]
[1, 3, 1]
[1, 4, 0]
[2, 0, 3]
[2, 1, 2]
[2, 2, 1]
[2, 3, 0]
[3, 0, 2]
[3, 1, 1]
[3, 2, 0]
[4, 0, 1]
[4, 1, 0]
[5, 0, 0]

如果这不仅仅是一个学习练习,那么您就没有必要使用自己的算法来生成分区:Python的标准库已经以函数的形式提供了您所需要的大部分内容

根据您链接到的上的定理2,有
n+k-1选择k-1
方法将
n
项划分为
k
存储箱,该定理的证明给出了组合和分区之间的明确对应关系。所以我们所需要的就是(1)生成这些组合的方法,(2)将每个组合转换为相应分区的代码。
itertools.combines
函数已经提供了第一个成分。对于第二种情况,每个组合给出了分隔器的位置;连续分隔器位置之间的差异(减1)给出了分区大小。代码如下:

import itertools

def partitions(n, k):
    for c in itertools.combinations(range(n+k-1), k-1):
        yield [b-a-1 for a, b in zip((-1,)+c, c+(n+k-1,))]

# Example usage
for p in partitions(5, 3):
    print(p)
下面是运行上述代码的输出

[0, 0, 5]
[0, 1, 4]
[0, 2, 3]
[0, 3, 2]
[0, 4, 1]
[0, 5, 0]
[1, 0, 4]
[1, 1, 3]
[1, 2, 2]
[1, 3, 1]
[1, 4, 0]
[2, 0, 3]
[2, 1, 2]
[2, 2, 1]
[2, 3, 0]
[3, 0, 2]
[3, 1, 1]
[3, 2, 0]
[4, 0, 1]
[4, 1, 0]
[5, 0, 0]

我需要解决同样的问题,找到了这篇文章,但我真的想要一个非递归的通用算法,不依赖itertools,也找不到,所以我想到了这个

默认情况下,生成器以词汇顺序(如前面的递归示例)生成序列,但
it2k = np.array([[i,j] for i,j in partitions(n,2)])
rng = np.arange(n+1)
np2k = np.vstack([rng, rng[::-1]]).T

(np2k == it2k).all()

>>> True