【问题标题】:All possible combinations of N objects in K bucketsK 个桶中 N 个对象的所有可能组合
【发布时间】:2021-06-26 13:07:20
【问题描述】:

假设我有 3 个标有 A、B、C 的盒子,我有 2 个球,B1 和 B2。我想在盒子里得到这些球的所有可能组合。请注意,重要的是要知道每个盒子里是哪个球,这意味着 B1 和 B2 不一样。

A         B         C
B1, B2
B1        B2
B1                  B2
B2        B1        
B2                  B1
          B1, B2
          B1        B2
          B2        B1
                    B1, B2

编辑

如果有解决这个问题的已知算法,请告诉我它的名字。

【问题讨论】:

  • @hilberts_drinking_problem 已修复。我最初是给出 2 个盒子的例子,为了更清楚,把它改成了 3 个。但我知道你知道这一点并且想要变得可爱。所以你去。
  • 您需要所有排列还是只需要总数?
  • 我抓住一切机会 :) 有(盒子数)^(球数)这样的组合。您是要全部列出还是要访问特定的组合?
  • @AKSingh 我需要所有排列
  • @hilberts_drinking_problem 我需要所有这些。我需要对它们应用启发式函数并在它们中的每一个上添加一些计算

标签: algorithm combinations permutation enumeration


【解决方案1】:

有一个非常简单的递归实现,在每个级别将当前球添加到每个框。处理完所有球后,递归结束。

这里有一些 Java 代码来说明。我们使用Stack 来表示每个框,因此我们可以在每一级递归之后简单地弹出最后添加的球。

void boxBalls(List<Stack<String>> boxes, String[] balls, int i)
{
    if(i == balls.length)
    {
        System.out.println(boxes);
        return;
    }
    
    for(Stack<String> box : boxes)
    {
        box.push(balls[i]);
        boxBalls(boxes, balls, i+1);
        box.pop();
    }
}

测试:

String[] balls = {"B1", "B2"};
List<Stack<String>> boxes = new ArrayList<>();
for(int i=0; i<3; i++) boxes.add(new Stack<>());

boxBalls(boxes, balls, 0);

输出:

[[B1, B2], [], []]
[[B1], [B2], []]
[[B1], [], [B2]]
[[B2], [B1], []]
[[], [B1, B2], []]
[[], [B1], [B2]]
[[B2], [], [B1]]
[[], [B2], [B1]]
[[], [], [B1, B2]]

【讨论】:

  • 谢谢。非常简单的解决方案。我希望我可以选择这两个答案,但我通常不喜欢递归函数,除非我必须这样做。这是我选择其他解决方案的唯一原因,但您的解决方案更容易遵循。再次感谢。
  • 我收回了。因为您的解决方案更简单,并且它使用 Stack 处理相同的对象,所以它的运行速度比其他算法快。我选这个。
  • 这个递归解决方案看起来非常简单。任何人都可以提出一个不会打印盒子但盒子会被一些“下一步”功能一个一个返回的解决方案吗?所以这个算法的调用者用“Next”函数可以得到一个一个的排列。
【解决方案2】:

设N 为桶数(示例中为3),M 球数(2)。现在,让我们看一下示例中[0..N**M) - [0..9) 范围内的数字;我们用radix = N 表示这些数字。对于问题中的示例,我们有 trinary 数字

现在我们可以很容易地解释这些数字:第一个数字显示第一个球的位置,第二个 - 第二个球的位置。

      |--- Second Ball position [0..2]
      ||-- First Ball position  [0..2]  
      ||
  0 = 00 - both balls are in the bucket #0 (`A`)
  1 = 01 - first ball is in the bucket #1 ('B'), second is in the bucket #0 (`A`)
  2 = 02 - first ball is in the bucket #2 ('C'), second is in the bucket #0 (`A`)
  3 = 10 - first ball is in the bucket #0 ('A'), second is in the bucket #1 (`B`)
  4 = 11 - both balls are in the bucket #1 (`B`)
  5 = 12 ...
  6 = 20
  7 = 21 ...
  8 = 22 - both balls are in the bucket #2 (`C`)

一般算法是:

  1. 对于0 .. N**M 范围内的每个数字
  2. ith 球 (i = 0..M-1) 将在桶中 #(number / N**i) % N(这里 / 代表 整数 除,% 代表余数)

如果你只想要总数,答案很简单N ** M,在上面的例子中3 ** 2 == 9

C#代码算法本身很容易实现:

static IEnumerable<int[]> BallsLocations(int boxCount, int ballCount) {
  BigInteger count = BigInteger.Pow(boxCount, ballCount);

  for (BigInteger i = 0; i < count; ++i) {
    int[] balls = new int[ballCount];
    int index = 0;

    for (BigInteger value = i; value > 0; value /= boxCount)
      balls[index++] = (int)(value % boxCount);

    yield return balls;
  }
}

是可以纠缠的答案表示:

static IEnumerable<string> BallsSolutions(int boxCount, int ballCount) {
  foreach (int[] balls in BallsLocations(boxCount, ballCount)) {
    List<int>[] boxes = Enumerable
      .Range(0, boxCount)
      .Select(_ => new List<int>())
      .ToArray();

    for (int j = 0; j < balls.Length; ++j)
      boxes[balls[j]].Add(j + 1);

    yield return string.Join(Environment.NewLine, boxes
      .Select((item, index) => $"Box {index + 1} : {string.Join(", ", item.Select(b => $"B{b}"))}"));
  }
}

演示:

  int balls = 3;
  int boxes = 2;

  string report = string.Join(
    Environment.NewLine + "------------------" + Environment.NewLine, 
    BallsSolutions(boxes, balls));

  Console.Write(report);

结果:

Box 1 : B1, B2, B3
Box 2 : 
------------------
Box 1 : B2, B3
Box 2 : B1
------------------
Box 1 : B1, B3
Box 2 : B2
------------------
Box 1 : B3
Box 2 : B1, B2
------------------
Box 1 : B1, B2
Box 2 : B3
------------------
Box 1 : B2
Box 2 : B1, B3
------------------
Box 1 : B1
Box 2 : B2, B3
------------------
Box 1 : 
Box 2 : B1, B2, B3

Fiddle

【讨论】:

  • 伪代码中的边界是否包含在内?我试过了,但它缺少一些案例。请check this implementation of it in C#
  • @Alireza Noori:请看我的编辑(C# 代码而不是伪代码)和小提琴dotnetfiddle.net/1QQMrH 算法本身很简单,但是以所需的方式表示它的答案需要时间
  • 非常感谢。新的编辑修复了它
猜你喜欢
  • 1970-01-01
  • 2020-07-16
  • 2012-10-11
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 2014-01-27
  • 1970-01-01
相关资源
最近更新 更多