是否有一种有效的算法可以找到总计 n 的所有 k 非负整数序列,同时避免旋转(完全,如果可能的话)? 顺序很重要,但对于我正在处理的问题,轮换是多余的。
例如,如果 k = 3且 n = 3,我希望获得如下列表:
(3,0,0),(2,1,0),(2,0,1),(1,1,1)。
元组(0,3,0)不应该在列表中,因为它是(3,0,0)的旋转。但是,(0,3,0)可以在列表中而不是(3,0,0)。请注意,(2,1,0)和(2,0,1)都在列表中 - 我不想避免所有元组的排列,只需轮换。此外,0是一个有效的条目 - 我没有找到 n 的分区。
我当前的程序是从超过1&lt; = i &lt; = n 循环,设置第一个条目等于 i ,然后递归地解决 n' = n - i 和 k' = k <的问题/ em> - 1.我通过强制要求没有条目严格大于第一个来获得一些加速,但是这种方法仍然会产生大量的旋转 - 例如,给定 n = 4并且 k = 3,(2,2,0)和(2,0,2)都在输出列表中。
编辑:添加粗体说明。我很抱歉没有像原来的帖子那样明确这些问题。
答案 0 :(得分:3)
您可以先生成分区(完全忽略顺序)作为元组(x_1,x_2,...,x_n)
其中x_i =我出现的次数。
所以Sum i * x_i = n。
我相信你已经知道如何做到这一点(来自你的评论)。
一旦你有了分区,你现在可以为此生成排列(将其视为多重集{1,1,...,2,2 ......,...}},其中我出现x_i次)使用这个问题的答案忽略了轮换:
Is there an algorithm to generate all unique circular permutations of a multiset?
希望有所帮助。
答案 1 :(得分:1)
您可以对解决方案进行排序,并以此方式消除轮换
OR
你可以尝试使你的递归解决方案构建只会被排序的元组
如何?这是我快速编造的东西
static list<tuple> tups;
void recurse(tuple l, int n, int k, int m)
{
if (k == 0 && n == 0)
{
tups.add(l);
return;
}
if (k == 0)
return;
if (k*m > n) //prunes out tuples that could not possibly be sorted
return;
else
for(int x = m; x <= n; x++)
recurse(l.add(x), n-x, k-1, x); //try only tuples that are increasing
}
用m = 0和初始步骤的空列表调用它。
这是一个C#控制台应用实现:http://freetexthost.com/b0i05jkb4e
哦,我在旋转假设中看到了我的错误,我认为你只是意味着排列,而不是实际的轮换。 但是,您可以扩展我的解决方案以创建独特增加元组的非旋转排列。我现在正在努力
答案 2 :(得分:1)
您需要按字典顺序生成Integer Partitions。
Here是一篇非常好的论文,具有快速算法。
HTH。
请注意,CAS programs通常会实现这些功能。例如,在Mathematica中:
Innput: IntegerPartitions[10, {3}]
Output: {{8, 1, 1}, {7, 2, 1}, {6, 3, 1},
{6, 2, 2}, {5, 4, 1}, {5, 3, 2},
{4, 4, 2}, {4, 3, 3}}