对于大输入,程序花费的时间太长

时间:2015-09-08 08:05:27

标签: c++ algorithm performance time-complexity integer-overflow

我使用的公式中我们必须找到 x 在给定 b 的值时可以采用的最大值。 x b 都只能采用非负整数值。等式是:

x^4+x^3+x^2+x+1≤b

我已经编写了以下代码(显然是愚蠢的)来解决它:

#include<iostream>
#include<climits>

using namespace std;

int main()
{
    unsigned long long b,x=0;
    cout<<"hey bro, value of b:";
    cin>>b;
    while(x++<b)
        if(x*x*x*x+x*x*x+x*x+x+1>b)
        break;
    if(b==0)
    cout<<"Sorry,no value of x satisfies the inequality"<<endl;
    else
    cout<<"max value of x:"<<x-1<<endl;
    return 0;
}

上述代码在b=LONG_MAX之前可以正常工作,但在b=LONG_LONG_MAXb=ULLONG_MAX之后,它会一直开始。如何才能解决此问题,使其最适合 b=ULLONG_MAX

8 个答案:

答案 0 :(得分:4)

如果对于x = m,不等式成立,那么它也适用于所有整数< m。如果它不适用于m,则它不会保留任何整数> m。这表明了什么算法?

如果您想破坏自己,请点击here查看算法。

答案 1 :(得分:3)

这不仅仅是一个优化问题。 (有关优化,请参阅IVlad的答案)。这也是一个正确性问题。对于非常大的值,表达式会导致整数溢出:简单地说,它从ULLONG_MAX回绕到零,并且你的循环继续没有检测到这一点。您需要在代码中构建溢出检测。

答案 2 :(得分:2)

旧答案(这里的实际问题不是迭代次数多,而是整数溢出;请从“更新”部分阅读;我将此部分保留在这里以了解错误假设的历史):

这些值非常大。当您的程序检查从0到LONG_LONG_MAX的每个值时,它会对9*10^12个操作进行调整,不是吗?对于ULLONG_MAX,我们有18*10^12次操作。尝试修改此程序以查看实际处理速度:

while (x++ < b)
{
    if (x % 1000000 == 0)
        cout << " current x: " << x << endl;
    if (x*x*x*x+x*x*x+x*x+x+1>b)
        break;
}

因此,您需要优化此算法(即减少迭代次数):由于您的函数为monotonic,因此您可以使用Binary search algorithm(请参阅Bisection method以获得说明)。< / p>

整数溢出也可能存在问题:对于大值x*x*x*x,函数x计算错误。想象一下你的类型是unsigned char(1个字节)。例如,当您的程序计算250*250*250*250时,您期望3906250000,但实际上您有3906250000 % 256(即16)。因此,如果x太大,则有可能您的函数将返回值< b(这将是奇怪的;理论上它可以制动您的优化算法)。好消息是,如果每次检查都正确,你就不会看到这个问题。但是对于更复杂的函数,您还需要支持长数学(例如,使用GMP或其他实现)。

更新:如何避免溢出风险?

我们需要找到x的最大允许值(让我们称之为xmax)。如果x,则允许值x*x*x*x+x*x*x+x*x+x+1 < ULLONG_MAX。因此,对初始问题(约x*x*x*x+x*x*x+x*x+x+1 < b)的答案不大于xmax。让我们找到xmax(只需在任何系统中求解等式x*x*x*x+x*x*x+x*x+x+1=ULLONG_MAX,例如WolframAlpha:anwer约为65535.75...,所以xmax==65535。所以,如果我们检查{ {1}}从x0我们不会出现溢出问题。它也是二进制搜索算法的初始值。

这也意味着,我们不需要在这里使用二进制搜索算法,因为它只需要检查65535个值。如果xmax没有回答,我们必须停止并返回回答x==65535

如果我们需要跨平台解决方案而不需要65536的硬编码,我们可以使用任何bigint实现(GMP或任何更简单的解决方案)或实现更准确的乘法和其他操作。示例:如果我们需要多层xmaxx,我们可以计算y并将此值与z=ULLONG_MAX/x进行比较。如果y,我们无法将z<yx相乘,而不会溢出。

答案 3 :(得分:2)

一个非常简单的观察在O(1)时间内解决了你的问题。

查找k = sqrt(sqrt(b))

如果k满足您的不平等,k就是您的答案。如果没有,k-1就是您的答案。

答案 4 :(得分:1)

您可以尝试找到一个上限并从那里开始工作。

// Find the position of the most significant bit.
int topBitPosition = 0;
while(b >> topBitPosition)
    topBitPosition++;
// Find a rough estimate of b ^ 1/4
unsigned long long x = b >> (topBitPosition - topBitPosition/4);
// Work down from there
while(x*x*x*x+x*x*x+x*x+x+1 > b)
    x--;
cout<<"max value of x:"<<x-1<<endl;

答案 5 :(得分:1)

不要让x超过65535。如果65535满足不等式,65536则不会。

答案 6 :(得分:0)

快速回答:

首先,你从x = 0开始然后增加它,这不是最佳解决方案,因为你正在寻找最大值而不是第一个。 因此,我会从一个可以

的上限出发

X = ABS((B)^(1/4))

比从该值减少,并且一旦找到元素&lt; = b,就完成了。

你甚至可以这样思考:

for y=b to 1
   solve(x^4+x^3+x^2+x+1=y)
   if has an integer solution then return solution

请参阅this

这是一个超级快速的答案我希望我没有写太多愚蠢的事情,对不起我还不知道如何在这里写数学。

答案 7 :(得分:-1)

这是一个稍微优化的版本:

#include<iostream>
int main()
{
    std::cout << "Sorry, no value of x satisfies the inequality" << std::endl;
    return 0;
}

为什么呢?因为x接近正无穷大,所以x^4+x^3+x^2+x+1是无界的。你的不平等没有b。计算机科学是数学的一个子集。