Python 一般酒吧及明星
我有一个用Python实现的算法,它将一个和的所有分解输出到3个容器中,用于从0到5的和。 我想概括一下我的代码,这样它就可以使用N个箱子(其中N小于最大和,即这里的5)。 模式是,如果有3个容器,则需要2个嵌套循环;如果有N个容器,则需要N-1个嵌套循环 有人能想出一种通用的方法来写这个,可能不使用循环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))
# 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