从一组x项中随机选择的n个项的所有可能组合(算法)

时间:2010-04-15 06:28:59

标签: c# c++ algorithm combinations

我有一组x字符串项,例如(“A”,“B”,“C”,“D”,“E”,“F”) 我需要知道计算n个项目的组合数量以及生成所有可能组合的算法的公式 例如 如果我们需要从列表中随机选择4个项目。 这4项可能是: (“A”,“B”,“C”,“D”)或 (“A”,“B”,“C”,“E”)或 (“A”,“B”,“C”,“F”)或 (“A”,“B”,“D”,“E”)......等 我需要一个公式来计算生成多少项而不重复,我们认为(“A”,“B”,“C”,“D”)作为我们不能考虑相同项目的结果组合之一作为另一个结果组合替换集合中的项目的位置(“A”,“B”,“D”,“C”) 此外,我需要在任何编程语言中生成所有可能组合的算法。 [C#,VB.NET,Java和C ++]

感谢您的帮助。

7 个答案:

答案 0 :(得分:11)

从n个项目中选择p,这是告诉你有多少组合的公式。

                  n!
n choose p  = -----------
               p! (n-p)!

Google计算器会为您做数学计算:

  

http://www.google.com/search?q=6+choose+4

     

6选择4 = 15

答案 1 :(得分:5)

你所描述的组合的公式在@Mark Harrison的回答中给出。然而,插入这个等式并且它会爆炸,因为数学意图取消。

例如,50选择49 - 这与选择要排除的元素相同,因此有50个选项。但是,公式需要您计算

   50!       3.04140932e64
-------- = ----------------- = 50
1! * 49!   1 * 6.08281864e62

你真正想要的等式x选择y是

x * (x-1) * ... * (x-n+1)
-------------------------
n * (n-1) * ... * 2 * 1

一些简单的C代码[请注意,这可以优化C(x,y)= C(x,x-y) - 这应该很容易从组合公式中看出]:

int c(int x, int y)
{
    int num = 1, denom = 1;
    int i;
    if (y > x-y)
        y = x - y;
    for (i = 0; i < y; ++i)
    {
        num *= (x - i);
        denom *= (y - i);
    }
    return num/denom;
}

所以,如果你想要所有可能的字母组合“ABCDEF”,你可以选择4个字母,即c(6,4)

答案 2 :(得分:3)

  

我需要使用任何编程语言生成所有可能组合的算法。

好的,这是Haskell中的单行解决方案:

import Data.List (subsequences)

n `outOf` xs = filter ((n ==) . length) (subsequences xs)

test = 4 `outOf` ["A", "B", "C", "D", "E", "F"]

*Main> test
[["A","B","C","D"],["A","B","C","E"],["A","B","D","E"],["A","C","D","E"],["B","C
","D","E"],["A","B","C","F"],["A","B","D","F"],["A","C","D","F"],["B","C","D","F
"],["A","B","E","F"],["A","C","E","F"],["B","C","E","F"],["A","D","E","F"],["B",
"D","E","F"],["C","D","E","F"]]
*Main> length test
15

答案 3 :(得分:1)

您需要二项式定理,并且需要嵌套循环。至于你的一种编程语言的实现,写起来并不困难。如果你环顾四周,你会发现这个问题经常被问到,因此你会发现有人投票决定关闭你的问题。

答案 4 :(得分:0)

您也可以选择Lexicographic ordering

这样的事情:

#include <stdio.h>

void print(const int *v, const int size)
{
    int i;
    if (v != 0) {
        for (i = 0; i < size; i++) {
            printf("%4d", v[i] );
        }
        printf("\n");
    }
} // print


void visit(int *Value, int N, int k)
{
    int i;
    static level = -1;
    level = level+1; Value[k] = level;

    if (level == N)
        print(Value, N);
    else
        for (i = 0; i < N; i++)
            if (Value[i] == 0)
                visit(Value, N, i);

    level = level-1; Value[k] = 0;
}


main()
{
    const int N = 4;
    int Value[N];
    int i;
    for (i = 0; i < N; i++) {
        Value[i] = 0;
    }
    visit(Value, N, 0);
}

答案 5 :(得分:0)

您可以使用Pascal's triangle计算组合数。要查找实际组合,可以使用普通递归。

答案 6 :(得分:0)

是的,Pascal的三角形有效。


int dp[MAX_X][MAX_Y] = {0};

dp[0][0] = 1;
for (int i = 1; i <= X; i++) {
    dp[i][0] = dp[i][i] = 0;
    for (int j = 1; j < min(i, Y + 1); j++)
        dp[i][j] = dp[i-1][j] + dp[i-1][j-1];
}

print(dp[X][Y])

或者,您可以使用滑动窗口技巧做一些事情。

然后,我认为公式效果更好,除非价值变得太大。