如何优化for循环?

时间:2011-01-26 08:50:30

标签: c++ algorithm numbers logic

我有一个问题,让我们说: 找到所有两对数字(x,y)(z,t),使x³+y³=z³+t³,其中< strong>(x,y)!=(z,t)和x³+y³&lt;万

取10,000个月的立方根21.544 - &gt;圆到21,所以我得到了:

#include <iostream>

using namespace std;

int main() {
    for( int x = 1; x <= 20; ++x ) {
        for( int y = x + 1; y <= 21; ++y ) {
            for( int z = x + 1; z <= y - 1; ++z ) {
                for( int t = z; t <= y - 1; ++t ) {
                    if( x*x*x + y*y*y == z*z*z + t*t*t ) {
                        cout << x << ", " << y << ", " << z << ", " << t << endl; 
                    }
                }
            } 
        }
    }
    return 0;
}

我知道这个代码可以进行更多优化,这就是我正在寻找的东西。另外,我的一个朋友告诉我, y 可能是 x + 2 而不是 x + 1 ,我怀疑这是否如果
x = 1 ,那么我们永远不会有 y = 2 ,在这种情况下错过了一个可能的解决方案。

有什么想法吗?

6 个答案:

答案 0 :(得分:8)

在给定当前循环结构的情况下,可以进行一种明显的算法优化,通过将范围限制为10,000的立方根,可以非常正确地进行优化。但是,根据10,000 - x的立方根,您可以更进一步限制y的范围。这是你可以做的一件事。

另一个优化是,地球上没有理由认为这应该是4个循环。只需做2个循环并计算x ^ 3 + y ^ 3的值并检查重复。 (这很好,如果你没有深入研究立方根的特征,你会得到的。) 这实际上并没有正确使用API​​,但您明白了这一点:

multimap<int, std::pair<int, int> > map;
for (int i = 1; i < 21; i++) {
    (for int j = x; j < cube_root(10000 - i^3); j++ {
        multimap.insert (i^3 + j^3, std::pair<int, int>(i,j);

然后你只需遍历多重图并寻找重复。

答案 1 :(得分:3)

典型权衡:速度记忆。

首先x上的界限非常大:如果我们假设(x,y)x <= y一起订购,那么

    x^3 + y^3 < N and x^3 < y^3 (for positive numbers)
=>  x^3 + x^3 < N (by transitivity)
<=> x^3 < N/2
<=> x <= floor((N/2)^(1/3))

因此x <= 17

现在,让我们记住x^3 + y^3的结果并构建一个关联表(sum - &gt;对)。顺便说一句,是否有理由将(x,x)作为一对丢弃?

int main(int argc, char* argv[])
{
  typedef std::pair<unsigned short, unsigned short> Pair;
  typedef std::vector<Pair> PairsList;
  typedef std::unordered_map<unsigned short, PairsList> SumMap;

  // Note: arbitrary limitation, N cannot exceed 2^16 on most architectures
  // because of the choice of using an `unsigned short`
  unsigned short N = 10000;
  if (argc > 1) { N = boost::lexical_cast<unsigned short>(argv[1]);  }

  SumMap sumMap;

  for (unsigned short x = 1; x*x*x <= N/2; ++x)
  {
    for (unsigned short y = x; x*x*x + y*y*y <= N; ++y)
    {
      sumMap[x*x*x + y*y*y].push_back(Pair(x,y));
    }
  }

  for (SumMap::const_reference ref: sumMap)
  {
    if (ref.second.size() > 1)
    {
      std::cout << "Sum: " << ref.first
                << " can be achieved with " << ref.second << "\n";
      // I'll let you overload the print operator for a vector of pairs
    }
  }

  return 0;
}

我们在这里是O(N ^ 2)。

答案 2 :(得分:2)

列出所有数字及其运算结果。按结果对列表进行排序。测试具有不同操作数的匹配结果。

答案 3 :(得分:2)

使用总和表格来生成该总和的数字对。

您可以通过两个嵌套for循环生成该表,然后运行表,使用多个解决方案收集总和。

答案 4 :(得分:2)

我建议计算外循环中的幂(编辑:从for循环中移出计算):

int x3, y3, z3;
for( int x = 1; x <= 20; ++x ) {
    x3 = x * x * x;
    for( int y = x + 1; y <= 21; ++y ) {
        y3 = y * y * y;
        for( int z = x + 1; z <= y - 1; ++z ) {
            z3 = z * z * z;
            for( int t = z; t <= y - 1; ++t ) {
                if( x3 + y3 == z3 + t*t*t ) {
                    cout << x << ", " << y << ", " << z << ", " << t << endl; 
                }
            }
        } 
    }
}

无论如何,你为什么要优化(至少在这个例子中)?这在我的电脑上运行20毫秒...所以我猜你在更大规模上有类似的问题。

答案 5 :(得分:1)

作为总摘要:

  • 在循环时而不是在结尾处计算立方体,因此{x}之后的int xcubed = x*x*x;(与y和z类似)。这可以节省您多次计算相同的值。把它们放在一张表中,这样你只需计算一次。
  • 使用某种程度的hash_table创建一个多维数据集总和表,并让它保留重复项(不要与散列碰撞混淆)。
  • 任何有重复的都是解决方案。
顺便提一下,1729应该是你的解决方案之一。 1立方加12立方,9立方+ 10立方。

为了测试性能,您当然可以选择更高的maxsum值(以及运行几次)。

算法严格为O(N ^ 2/3)。 (2/3,因为你只去N的立方根,然后在那个较小的范围内是O(m ^ 2)。