【问题标题】:find all combinations that have the same sum more efficiently更有效地找到具有相同总和的所有组合
【发布时间】:2019-04-14 10:26:52
【问题描述】:

我想找到 -n 到 n 范围内四个数字的所有组合,它们加起来为零。有没有有效的算法来解决这个问题?

#include <iostream>
using namespace std;

int main()
{
    int i, j, k, l;
    int size = 20;

    for (i = -size; i <= size; i++)
    {
        for (j = -size; j <= size; j++)
        {
            for (k = -size; k <= size; k++)
            {
                for (l = -size; l <= size; l++)
                {
                    if (i + j + k + l == 0)
                    {
                        cout << i << " " << j << " " << " " << k << " " << l << endl;
                    }
                }
            }

        }
    }
    return 0;

}

【问题讨论】:

  • 是的,这类问题通常通过某种形式的动态规划来解决。我想说这个问题属于cs.stackexchange.com
  • 是np难题吗?
  • 您不必考虑所有数字为正数或所有数字为负数
  • @learning_cpp np 难有什么意义?这不是决策问题。我猜想组合的数量可能是 n 的指数函数。所以不,不可能有多项式解决方案。
  • @Quimby 你是对的,所以看起来问题在自然界中解决起来很昂贵

标签: c++ combinations


【解决方案1】:

可能有很多方法可以优化这个算法,但这里有几个简单的。

首先,您根本不需要通过数字的最终循环:

for (l = -size; l <= size; l++)
    ...

这是因为现在已经定义了前三个数字,因此只有一个可能的数字可以使所有 4 加起来为零。您所要做的就是找出那个数字是多少,并检查它是否在 -n 到 +n 的范围内。

int l = 0 - (i+j+k);
if (-l >= -size && l <= size)
     ....

其次,在许多情况下可以缩短第三个循环,例如,如果 i 和 j 都是 -size,则唯一可能导致所有四个数字加起来为零的 k 值是 +size。使用这个想法,我们可以在这个循环上设置额外的界限,在相当多的情况下缩短它。

这两个优化应该会显着提高该算法的速度。

【讨论】:

  • 这是聪明的改进!但是这个问题可以在多项式时间内解决吗?假设我有更大的尺寸和更深的循环。在傅立叶空间中集成函数时遇到这个问题
  • 考虑到这一点,几乎可以肯定有更快的方法。从两个数字的简单情况开始,一组解在 x+y=0 行上。三个数字定义一个平面,四个数字定义一个超平面。您应该能够计算此超平面与限制输入的原点对齐超立方体的交点。您应该能够使用三个循环遍历超平面,每次都生成解决方案。
【解决方案2】:

查看我的代码和 cmets 。 算法效率为O(N^3),解的总数也是O(N^3)。

#include <cstdio>
#include <algorithm>


int main(){
      int size = 20;
       for(int a = -size; a <= size; ++a){
            for(int b = -size; b <= size; ++b ) {
                 int c_min, c_max, d, c;
                 //1.  a + b + c +d = 0.
                 //2.  d = -(a+b+c)   
                 //3.   -size <= d <= size
                 //4.  -size <= -(a+b+c) <= size
                 //5.  size >= a +b + c >= -size
                 //6.  -size - (a+b) <= c <= size - (a+b)
                 //7. but,    -size <= c <= size.
                c_min = std::max(-size, -size - (a+b) ) ;
                c_max = std::min(size, size - (a+b) ) ;
                for(c = c_min ; c <= c_max; ++c){
                      d = -(a+b+c);
                      printf("a = %d b = %d  c = %d  d= %d\n", a,b,c,d);                          
                }
            }
       }

   return 0;
}

【讨论】:

    猜你喜欢
    • 2019-02-01
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 2016-04-03
    • 1970-01-01
    • 2018-10-26
    相关资源
    最近更新 更多