我想迭代一个的所有顶点n
尺寸为 1 的维度立方体。我知道我可以做到这一点itertools.product
如下:
>>> n = 3
>>> for j in it.product((0,1), repeat=n) :
... print j
...
(0, 0, 0)
(0, 0, 1)
(0, 1, 0)
(0, 1, 1)
(1, 0, 0)
(1, 0, 1)
(1, 1, 0)
(1, 1, 1)
但我需要根据顶点的数量来区别对待每个顶点1
在其坐标中找到 s,即(0, 1, 1)
, (1, 0, 1)
and (1, 1, 0)
都会受到相同的待遇,因为他们都有两个1
s。而不是使用上面的迭代器,然后计数1
s,我想生成按数量排序的笛卡尔积1
s,大致如下:
>>> for ones in xrange(n) :
... for seq in magic_expression(ones, n) :
... print ones, seq
...
0 (0, 0, 0)
1 (0, 0, 1)
1 (0, 1, 0)
1 (1, 0, 0)
2 (0, 1, 1)
2 (1, 0, 1)
2 (1, 1, 0)
3 (1, 1, 1)
我的高中数学老师会这样称呼这些2 个元素的排列n
一次,第一个元素重复n - ones
次,以及第二次ones
times,并且很容易证明有n! / ones! / (n - ones)!
其中。
根据维基百科 http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order我可以按字典顺序生成它们,如下所示:
def lexicographical(ones, n) :
perm = [0] * (n - ones) + [1] * ones
yield tuple(perm)
while True :
k = None
for j in xrange(n - 1) :
if perm[j] < perm[j + 1] :
k = j
if k is None :
break
l = k + 1
for j in xrange(k + 2, n) :
if perm[k] < perm[j] :
l = j
perm[k], perm[l] = perm[l], perm[k]
perm[k+1:] = perm[-1:k:-1]
yield tuple(perm)
但计时起来,这只会在计算完整的笛卡尔积时开始得到回报n >= 10
,然后仅对于ones < 2
,这不是典型的用例。有没有一种优雅的方法来加速我上面的代码,也许有一些强大的itertools
巫术,还是完全使用不同的算法?如果有什么区别的话,我不在乎产生的排列的顺序。或者我应该放弃计数?
EDIT