列出所有 k 元组,其中条目总和为 n,忽略旋转

发布于 2024-09-24 03:12:06 字数 766 浏览 5 评论 0原文

是否有一种有效的算法来查找总和为 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 <= i <= n 开始循环,将第一个条目设置为 i,然后递归解决 n' = n - ik' = k 的问题- 1. 通过强制没有条目严格大于第一个条目,我获得了一些加速,但这种方法仍然会产生大量旋转 - 例如,给定 n = 4 和 k = 3,(2,2,0)和(2,0,2)都在输出列表中。

编辑:以粗体添加了说明。我很抱歉没有在原来的帖子中阐明这些问题。

Is there an efficient algorithm for finding all sequences of k non-negative integers that sum to n, while avoiding rotations (completely, if possible)? The order matters, but rotations are redundant for the problem I'm working on.

For example, with k = 3 and n = 3, I would want to get a list like the following:

(3, 0, 0), (2, 1, 0), (2, 0, 1), (1, 1, 1).

The tuple (0, 3, 0) should not be on the list, since it is a rotation of (3, 0, 0). However, (0, 3, 0) could be in the list instead of (3, 0, 0). Note that both (2, 1, 0) and (2, 0, 1) are on the list -- I do not want to avoid all permutations of a tuple, just rotations. Additionally, 0 is a valid entry -- I am not looking for partitions of n.

My current procedure is to loop from over 1 <= i <= n, set the first entry equal to i, and then recursively solve the problem for n' = n - i and k' = k - 1. I get some speed-up by mandating that no entry is strictly greater than the first, but this approach still generate a lot of rotations -- for example, given n = 4 and k = 3, both (2,2,0) and (2,0,2) are in the output list.

Edit: Added clarifications in bold. I apologize for not making these issues as clear as I should have in the original post.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

节枝 2024-10-01 03:12:07

您可以对解决方案进行排序并消除旋转。

您可以尝试使您的递归解决方案构建只能如何排序的元组

?这是我快速编造的东西

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

哦,我看到我的旋转假设的错误,我认为你只是指排列,而不是实际的旋转。
但是,您可以扩展我的解决方案以创建唯一递增元组的非旋转排列。我现在正在努力

You could just sort your solutions and eliminate rotations that way.
OR
you can try to make your recursive solution build tuples that will only ever be sorted

how? here's something I made up quickly

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
}

call this with m = 0 and an empty list for the initial step.

here's a C# console app implementation : http://freetexthost.com/b0i05jkb4e

Oh, I see my mistake in the assumption of rotation, I thought you just meant permutations, not an actual rotation.
However, you can extend my solution to create non-rotational permutations of the unique increasing tuples. I'm working on it now

埖埖迣鎅 2024-10-01 03:12:07

您需要按字典顺序生成整数分区

这里是一篇非常好的论文,具有快速算法。

HTH。

请注意,CAS 程序通常实现这些功能。例如在 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}}

You need to generate Integer Partitions in lexicographical order.

Here is a very good paper with fast algorithms.

HTH.

Note that CAS programs usually implement these functions. For example in 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}}
水染的天色ゝ 2024-10-01 03:12:06

您可以首先将分区(完全忽略顺序)生成为元组 (x_1, x_2, ..., x_n),

其中 x_i = i 出现的次数。

所以求和 i* x_i = n。

我相信您已经知道如何做到这一点(根据您的评论)。

一旦有了分区,您现在就可以为此生成排列(将其视为多重集 {1,1,...,2,2...,...n},其中 i 出现 x_i 次),该排列忽略旋转,使用这个问题的答案:

是否有一种算法可以生成多重集的所有唯一循环排列?

希望有帮助。

You can first generate the partitions (which ignore order completely) as a tuple (x_1, x_2, ..., x_n)

where x_i = number of times i occurs.

So Sum i* x_i = n.

I believe you already know how to do this (from your comments).

Once you have a partition, you can now generate the permutations for this (viewing it as a multiset {1,1,...,2,2...,...n}, where i occurs x_i times) which ignore rotations, using the answer to this question:

Is there an algorithm to generate all unique circular permutations of a multiset?

Hope that helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文