我有这个计算 n选择k 的c#类,然后按字典顺序生成所有可能的组合。它还可以返回每个组合的订单号,例如:如果选择k(30,5),则传递[1,2,3,4,5]将返回1,而[26,27,28,则为142506, 29,30]。
有没有办法退回包含部分组合的所有订单号?因此,如果我通过[1,2,3,4],它将返回:1,2,3,... 25,26。
1: [1,2,3,4,5]
2: [1,2,3,4,6]
3: [1,2,3,4,7]
...
25: [1,2,3,4,29]
26: [1,2,3,4,30]
我需要这个用于抽奖。我希望每张票都有它的组合号码,我需要在绘制5个球的每一个时显示可能的赢家总数。现在每张票都有实际的组合,我运行一个查询来获得部分获胜者,但我想优化这个过程。
答案 0 :(得分:3)
您需要的是一个函数,对于组合[a,b,c,d,e],返回该组合的订单号。然后你可以得到组合集(可能数字的集合减去已经选择的数字)选择(你还没有选择的数量),添加已经选择到每个组合的数字,重新排序每个组合,并使用获取订单号的功能。
编辑:这可能会有所帮助:saliu.com/bbs/messages/348.html
EDIT2:答案就在这里:How to calculate the index (lexicographical order) when the combination is given
EDIT3:我为此尝试了一些C#代码:
private IEnumerable<int[]> CombinationsFor(int n, int k);
private int CombinationsCount(int n, int k);
private int IndexFor(int n, int[] combination)
{
int k = combination.Count();
int ret = 0;
int j = 0;
for (int i = 0; i < k; i++)
{
for (j++; j < combination[i]; j++)
{
ret += CombinationsCount(n - j, k - i - 1);
}
}
return ret;
}
private IEnumerable<int> PossibleCombinations(int n, int k, int[] picked)
{
int m = picked.Count();
int[] reverseMapping = Enumerable.Range(0, n)
.Where(i=>!picked.Contains(i))
.ToArray();
return CombinationsFor(n-m, k-m)
.Select(c => c
.Select(x=>reverseMapping[x])
.Concat(picked)
.OrderBy(x=>x)
.ToArray()
)
.Select(c => IndexFor(n, c));
}
答案 1 :(得分:3)
您需要的组合是(n-d) choose (k-d)
,其中d
是固定抽奖的数量。
当你生成它们时,它们将没有正确的数字(它们正在跳过最后的d
数字而不是你想要的数字),而只是使用子列表的反向顺序映射来重新组合你的组合:
(在伪python代码中,因为这与C#完全无关)
listing = [1, 2, ..., 30]
partial = [4, 7, 25]
draw_size = 5
remaining = listing - partial
reverse_order_mapping = [(index, item) in remaining.items_and_indexes]
n = listing.size // 30
k = draw_size // 5
d = partial.size // 3
for comb in ((n-d) choose (k-d))
actual_comb = comb.map(reverse_order_mapping)
print actual_comb
end
然后,您只需使用生成的组合调用您的函数(在需要时对其进行排序)。