我想编写一个函数来生成一个元组数组,其中包含C ++中M个框中所有可能的N个球的排列。
顺序(编辑:在结果列表中)并不重要,只是第一个必须是(N,0,...,0)和最后一个(0,0,...,N)。 / p>
我没有在C ++网上找到这样的实现,只有字符的排列或排列数的计算......
有什么想法吗?
答案 0 :(得分:10)
解决这个问题有一个巧妙的技巧。想象一下,我们把 n 球和 m - 1个盒子放在一行,长度为 n + m - 1(盒子中的盒子混合在一起)。然后将每个球放在右侧的方框中,并在右侧添加一个 m 的方框,以获得剩下的任何球。
这会在 m 框中产生 n 球的排列。
很容易看出 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
它不是在提升中,而是遵循从名称中容易看到的相同原则。