C ++中M盒中N个球的组合列表

时间:2011-06-28 14:46:20

标签: c++ permutation combinations

我想编写一个函数来生成一个元组数组,其中包含C ++中M个框中所有可能的N个球的排列。

顺序(编辑:在结果列表中)并不重要,只是第一个必须是(N,0,...,0)和最后一个(0,0,...,N)。 / p>

我没有在C ++网上找到这样的实现,只有字符的排列或排列数的计算......

有什么想法吗?

4 个答案:

答案 0 :(得分:10)

解决这个问题有一个巧妙的技巧。想象一下,我们把 n 球和 m - 1个盒子放在一行,长度为 n + m - 1(盒子中的盒子混合在一起)。然后将每个球放在右侧的方框中,并在右侧添加一个 m 的方框,以获得剩下的任何球。

row containing a box, two balls, a box, one ball, a box, one ball, and an imaginary box

这会在 m 框中产生 n 球的排列。

row of boxes containing zero, two, one, and one ball respectively

很容易看出 n 球与 m - 1盒(第一张图片)的顺序排列相同,因为有排列 m 框中的 n 球。 (换一种方式,将每个球放在右边的方框中;另一方面,每个方框将球排空到左边的位置。)第一张图中的每个排列由我们放置的位置决定。框。有 m - 1个框和 n + m - 1个位置,所以有 n + m - 1 C m - 1 方法。

所以你只需要一个普通的组合算法(see this question)来生成盒子的可能位置,然后取连续位置之间的差值(小于1)来计算每个盒子中的球数。 / p>

在Python中,它非常简单,因为标准库中有combinations算法:

from itertools import combinations

def balls_in_boxes(n, m):
    """Generate combinations of n balls in m boxes.

    >>> list(balls_in_boxes(4, 2))
    [(0, 4), (1, 3), (2, 2), (3, 1), (4, 0)]
    >>> list(balls_in_boxes(3, 3))
    [(0, 0, 3), (0, 1, 2), (0, 2, 1), (0, 3, 0), (1, 0, 2), (1, 1, 1), (1, 2, 0), (2, 0, 1), (2, 1, 0), (3, 0, 0)]

    """
    for c in combinations(range(n + m - 1), m - 1):
        yield tuple(b - a - 1 for a, b in zip((-1,) + c, c + (n + m - 1,)))

答案 1 :(得分:1)

M个框中N个球的组合列表= k +每个k从0到N的(M-1)个框中的(N-k)个球的组合列表。尝试递归编码。

答案 2 :(得分:1)

您可以使用向量队列递归地解决此问题,其中您有一个带有for循环的函数,循环遍历N个球的数量,将每个N个球放在M盒的一个单独的框中通过大小为M的向量。然后递归调用相同的函数,但传递一个简化的索引值,以便在向量中设置N个球的值。递归调用的基本情况将使用大小为M的向量初始化队列,并且将创建N个向量,其中每个向量具有初始化时隙(在这种情况下为时隙0),其设置有来自N个球的单独值。 / p>

编辑: 我已经更改了代码,现在它反映了多种组合,而不是排列。这需要添加一个新的struct box_t,允许使用它来正确地存储队列中的框,并告诉我们何时达到重复。

struct box_t
{
    vector<int> boxes;
    int flag;  //this flag lets us know if we're repeating a value
    box_t(int num_boxes): boxes(num_boxes), flag(0) {}
};

typedef queue<box_t> comb_queue;

comb_queue multi_combinations(int num_boxes, int ball_index)
{
    if (ball_index == 0)
    {
        comb_queue initial_queue;

        //initialize our queue with M vectors that will have 
        //only one of the "boxes" initialized with a value
        for (int i=0; i < num_boxes; i++)
        {
            box_t temp(num_boxes);
            temp.boxes[i] += 1;
            initial_queue.push(temp);
        }

        return initial_queue;
    }

    //here is our recursive call
    comb_queue box_combinations = multi_combinations(num_boxes, ball_index - 1);
    int queue_size = box_combinations.size();

    for (int i=0; i < queue_size; i++)
    {
        box_t boxes = box_combinations.front();
        box_combinations.pop();

        if (boxes.flag)
        {
            //this combination has already been processed, so place back in the queue
            //and move on
            box_combinations.push(boxes);
            continue;
        }

        for (int j=0; j < num_boxes; j++)
        {
             //increment the ball-count in each of the boxes
             boxes[j] += 1;
             box_combinations.push(boxes);

             //remove the ball we just added from the box slot for the next loop
             boxes[j] -= 1;
        }

        //finally place the box_t we've been processing back in the queue, but with the
        //repeat flag set
        boxes.flag = 1;
        box_combinations.push(boxes);
    }

    return box_combinations;
}

然后调用函数:

comb_queue all_multi_combinations = multi_combinations(M, (N-1));

输出现在将是一个向量队列,每个盒子中的球数包含M个盒子中N个球的每个多组合。

答案 3 :(得分:0)

实际上有一个。看看:http://photon.poly.edu/~hbr/boost/combinations.html

它不是在提升中,而是遵循从名称中容易看到的相同原则。