我正在尝试解决Project Euler问题之一。因此,我需要一种算法来帮助我以任何顺序查找集合的所有可能分区。
例如,给定集合2 3 3 5
:
2 | 3 3 5
2 | 3 | 3 5
2 | 3 3 | 5
2 | 3 | 3 | 5
2 5 | 3 3
等等。几乎所有组合成员的组合。我当然搜索了网络,但是找不到对我有用的东西,因为我说程序员而不是高级数学。
任何人都可以帮我解决这个问题吗?我几乎可以阅读任何编程语言,从BASIC到Haskell,所以用你想要的任何语言发布。
答案 0 :(得分:2)
您是否考虑过搜索树?每个节点都表示选择放置元素的位置,叶节点是答案。我不会给你代码,因为这是Project Euler乐趣的一部分;)
答案 1 :(得分:1)
看看:
The Art of Computer Programming, Volume 4, Fascicle 3: Generating All Combinations and Partitions
<强> 7.2.1.5。生成所有设置分区
答案 2 :(得分:0)
嗯,问题有两个方面。
第一,这些物品可以按任何顺序排列。所以对于N个项目,有N个!排列(假设项目被视为唯一的)
其次,您可以将分组设想为每个项目之间的一个标记,表示分隔。这些标志中将有N-1个,因此对于给定的排列,将有2 ^(N-1)个可能的分组。
这意味着对于N个项目,总共会有N!*(2 ^(N-1)个)分组/排列,它们变得非常快。
在您的示例中,前四项是一个排列的分组。最后一项是另一种排列的分组。您的商品可以被视为:
2 on 3 off 3 off 5
2月3日3关5
2月3日3月5日
2月3日3月5日
2关5 on 3 off 3
排列(显示的顺序)可以通过像树一样看待它们,如另外两个所提到的那样。这几乎肯定会涉及递归,例如here。 分组在很多方面与它们无关。获得所有排列后,如果需要,可以将它们与分组链接。
答案 3 :(得分:0)
一般情况下,我会看一下用于计算配置数量的递归结构,并构建一个类似的递归来枚举它们。最好是计算整数和配置之间的一对一映射。这适用于排列,组合等,并确保每个配置只枚举一次。
现在即使recursion for the number of partitions of some identical items也相当复杂。
对于多集的分区,计数相当于解决Project Euler problem 181到任意多集的泛化。
答案 4 :(得分:0)
以下是此部分问题所需的代码:
def memoize(f):
memo={}
def helper(x):
if x not in memo:
memo[x]=f(x)
return memo[x]
return helper
@memoize
def A000041(n):
if n == 0: return 1
S = 0
J = n-1
k = 2
while 0 <= J:
T = A000041(J)
S = S+T if k//2%2!=0 else S-T
J -= k if k%2!=0 else k//2
k += 1
return S
print A000041(100) #the 100's number in this series, as an example
答案 5 :(得分:-1)
我很快就掀起了一些代码来做到这一点。但是,我遗漏了将给定列表的每个可能组合分开,因为我不确定它实际上是否需要,但如果需要,它应该很容易添加。
无论如何,代码在少量时运行得相当好,但是,正如CodeByMoonlight已经提到的那样,可能性非常快,因此运行时也会相应增加。
无论如何,这是python代码:
import time
def separate(toseparate):
"Find every possible way to separate a given list."
#The list of every possibility
possibilities = []
n = len(toseparate)
#We can distribute n-1 separations in the given list, so iterate from 0 to n
for i in xrange(n):
#Create a copy of the list to avoid modifying the already existing list
copy = list(toseparate)
#A boolean list indicating where a separator is put. 'True' indicates a separator
#and 'False', of course, no separator.
#The list will contain i separators, the rest is filled with 'False'
separators = [True]*i + [False]*(n-i-1)
for j in xrange(len(separators)):
#We insert the separators into our given list. The separators have to
#be between two elements. The index between two elements is always
#2*[index of the left element]+1.
copy.insert(2*j+1, separators[j])
#The first possibility is, of course, the one we just created
possibilities.append(list(copy))
#The following is a modification of the QuickPerm algorithm, which finds
#all possible permutations of a given list. It was modified to only permutate
#the spaces between two elements, so it finds every possibility to insert n
#separators in the given list.
m = len(separators)
hi, lo = 1, 0
p = [0]*m
while hi < m:
if p[hi] < hi:
lo = (hi%2)*p[hi]
copy[2*lo+1], copy[2*hi+1] = copy[2*hi+1], copy[2*lo+1]
#Since the items are non-unique, some possibilities will show up more than once, so we
#avoid this by checking first.
if not copy in possibilities:
possibilities.append(list(copy))
p[hi] += 1
hi = 1
else:
p[hi] = 0
hi += 1
return possibilities
t1 = time.time()
separations = separate([2, 3, 3, 5])
print time.time()-t1
sepmap = {True:"|", False:""}
for a in separations:
for b in a:
if sepmap.has_key(b):
print sepmap[b],
else:
print b,
print "\n",
它基于QuickPerm算法,您可以在此处详细了解:QuickPerm
基本上,我的代码会生成一个包含n个分色的列表,将它们插入到给定的列表中,然后查找列表中所有可能的分色排列。
所以,如果我们使用你的例子,我们会得到:
2 3 3 5
2 | 3 3 5
2 3 | 3 5
2 3 3 | 5
2 | 3 | 3 5
2 3 | 3 | 5
2 | 3 3 | 5
2 | 3 | 3 | 5
在0.000154972076416秒。
但是,我仔细阅读了您正在进行的问题的问题描述,并且我看到您是如何尝试解决这个问题的,但是看看运行时间增加的速度,我认为它不会像您期望的那样快。请记住,项目欧拉的问题应该在一分钟左右解决。