从4个输入数字中查找所有可能的组合,最多可添加24个

时间:2012-05-16 07:19:17

标签: algorithm

实际上,这个问题可以概括如下:

  

从满足的给定元素集中查找所有可能的组合   一定的标准。

那么,有什么好的算法吗?

8 个答案:

答案 0 :(得分:9)

只有16种可能性(其中一种是将“它们都没有”加在一起,这不会给你24),所以老式的“蛮力”算法看起来对我很好:< / p>

for (unsigned int choice = 1; choice < 16; ++choice) {
    int sum = 0;
    if (choice & 1) sum += elements[0];
    if (choice & 2) sum += elements[1];
    if (choice & 4) sum += elements[2];
    if (choice & 8) sum += elements[3];
    if (sum == 24) {
        // we have a winner
    }
}

在问题的完全一般形式中,判断组合是否符合“特定标准”的唯一方法是评估每个组合的标准。如果有关标准的更多信息,也许您可​​以通过一些方法来避免测试每个组合并相应地构建算法,但不能没有这些细节。再一次,蛮力为王。

答案 1 :(得分:2)

WikipediaMathWorld中有关于总和问题的两个有趣解释。

在您提出的第一个问题的情况下,第一个答案对于有限数量的元素是有益的。你应该意识到Jessop先生使用16作为他的循环边界的原因是因为这是2 ^ 4,其中4是你集合中元素的数量。如果你有100个元素,那么循环限制将变为2 ^ 100,你的算法将永远完成。

如果是有界总和,则应考虑深度优先搜索,因为当元素总和超过您要查找的总和时,您可以修剪分支并回溯。

在通用问题的情况下,找到满足特定标准的元素子集,这称为背包问题,已知为NP-Complete。鉴于此,没有算法可以在不到指数的时间内解决它。

然而,有几种启发式方法可以带来很好的结果,包括(但不限于)遗传算法(我个人喜欢,因为我写了一本关于它们的书)和动态编程。在Google中进行的简单搜索将显示许多科学论文,这些论文描述了针对此问题的不同解决方案。

答案 2 :(得分:1)

  

从给定的元素集中查找所有可能的组合   符合某个标准

如果我理解你,这段代码对你有帮助:

    >>> from itertools import combinations as combi    
    >>> combi.__doc__
'combinations(iterable, r) --> combinations object\n\nReturn successive r-length
 combinations of elements in the iterable.\n\ncombinations(range(4), 3) --> (0,1
,2), (0,1,3), (0,2,3), (1,2,3)'
    >>> set = range(4)
    >>> set
    [0, 1, 2, 3]
    >>> criteria = range(3)
    >>> criteria
    [0, 1, 2]
    >>> for tuple in list(combi(set, len(criteria))):
    ...     if cmp(list(tuple), criteria) == 0:
    ...             print 'criteria exists in tuple: ', tuple
    ...
    criteria exists in tuple:  (0, 1, 2)

    >>> list(combi(set, len(criteria)))
    [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]

答案 3 :(得分:0)

一般来说,对于一个问题,你必须尝试所有的姿势,如果你知道它不符合标准,你应该做的事情让代码中止组合的建立(如果你的标准是你没有更多那么两个蓝色的球,然后你必须中止有两个以上的计算)。 Backtracing

def perm(set,permutation): 
    if lenght(set) == lenght(permutation):
       print permutation
    else:
        for element in set:
           if permutation.add(element) == criteria:
               perm(sett,permutation)
           else:
                permutation.pop()  //remove the element added in the if 

答案 4 :(得分:0)

输入数字的集合很重要,正如您可以在你的开始集中的负数,虚数,有理数等。你也可以限制为例如所有偶数,所有奇数输入等。

这意味着很难构建一些演绎效果。你需要蛮力,a.k.a.尝试每一个组合等。

在这个特殊的问题中你可以建立一个递归的算法 - 例如找到3个Int(1,22)的每个组合,最多可加23个,然后加1个,每个组合加22个并加2个等等。这可以再次分成2个加起来21个等的每个组合。需要决定你是否可以计算两次相同的数字。

一旦你有了一个递归函数来调用 -

combinations( 24 , 4 ) = combinations( 23, 3 ) + combinations( 22, 3 ) + ... combinations( 4, 3 );
combinations( 23 , 3 ) = combinations( 22, 2 ) + ... combinations( 3, 2 );

这很有效,除了你必须小心在递归中重复数字。

答案 5 :(得分:0)

    private int[][] work()
    {
        const int target = 24;
        List<int[]> combos = new List<int[]>();

        for(int i = 0; i < 9; i++)
            for(int x = 0; x < 9; x++)
                for(int y = 0; y < 9; y++)
                    for (int z = 0; z < 9; z++)
                    {
                        int res = x + y + z + i;
                        if (res == target)
                        {
                            combos.Add(new int[] { x, y, z, i });
                        }
                    }
        return combos.ToArray();
    }

它立即起作用,但可能有更好的方法,而不是'猜测和检查'。我正在做的就是遍历各种可能性,将它们全部加在一起,看看它是否达到了目标值。

答案 6 :(得分:0)

如果我正确理解你的问题,你所要求的是“排列”或可能的排列(X)数字的数字(N)从一组(Y)数字中取出。

N = Y! / (Y - X)!  

我不知道这是否会有所帮助,但这是我想出的关于排列作业的解决方案。

您使用substr函数

输入:123(字符串)

1)将每个输入数字放入一个数组

array[N1,N2,N3,...]

2)创建交换功能

function swap(Number A, Number B)
{
   temp = Number B 
   Number B = Number A   
   Number A = temp   
}

3)此算法使用交换函数移动数字,直到完成所有排列。

original_string= '123'    
temp_string=''

While( temp_string != original_string)
{
   swap(array element[i], array element[i+1])

   if (i == 1)
       i == 0

   temp_string = array.toString
   i++
}

希望您可以遵循我的伪代码,但这至少适用于3位数的排列

答案 7 :(得分:0)

(n X n) 建立了一个nxn

的方阵

并将所有相应的交叉值打印在一起

e.g。

1 2 3 4

1 11 12 13 14

2 .. .. .. ..

3 ..

4 .. ..