我不是 C# 专家,所以我会给你一个纯粹的数学解决方案,希望你能用你的语言翻译它。
基本上,您的任务由两个独立的部分组成:选择 b 组 i 到 j 个元素,以及随机性。第二个应该很容易 - 最初只是随机打乱元素,然后进行组拆分。让我们来看看有趣的部分:
如何将 n 个元素分成b
包含每个元素的组?一个直接的解决方案是在第一组的元素数量之间取随机数,然后是第二组,等等。但是,不能保证这样做你不会留下最后一组元素编号不在和之间。这种解决方案也不是纯粹的随机分布。i
j
i
j
i
j
正确的方法是获取第一组的元素数量,当您采用尽可能多的元素时,尊重整体组分裂的解决方案的概率 - 您基本上感兴趣的是总体上有多少解决方案task(n, b, i, j)
以及存在多少解决方案task(n-k, b-1, i, j)
如果我们假设我们k
在第一组中取元素。如果我们能够仅计算解决方案的数量,您可以取每个 k 及其各自的概率,并对第一组的 k 进行随机抽样,然后是第二组,依此类推......
所以现在的问题是:有多少解决方案task(n, b, i, j)
?请注意,task(n, b, i, j) = sum(k=i to j) task(n-k, b - 1, i, j)
您可以使用递归轻松找到这些数字(使用动态优化,因此您无需多次计算这些值)。
PS:解决方案的数量可能有一个封闭形式的解决方案,但我无法立即弄清楚,只要n * b
保持相对较小(< 10 ^ 6)递归解决方案应该可以工作。
编辑
PS2:实际上,其中的数字task(n, b, i, j)
可能会很快变得非常大,因此请考虑使用大整数。