由于输入量大,程序耗时太长

Program taking too long for large input

本文关键字:程序 于输入 输入      更新时间:2023-10-16

我正在使用一个方程,在这个方程中,我们必须找到给定b的值,x可以取的最大值。xb都只能取非负整数值。公式为:

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 ?

如果对于x = m,不等式成立,则对于所有整数< m也成立。如果它对m不成立,那么它对> m也不成立。这说明了什么算法?

如果你想宠坏自己,点击这里查看算法

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

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

查找k = sqrt(sqrt(b))

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

旧答案(这里真正的问题不是迭代次数太多,而是整数溢出;请阅读"更新"部分;我把这部分保留在这里,以记录错误假设的历史):

这些值非常大。当你的程序检查从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;
}

所以,你需要优化这个算法(即减少迭代次数):因为你的函数是单调的,你可以使用二分搜索算法(参见二分法也说明)。

还有一个可能的整数溢出问题:函数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+1 < ULLONG_MAX,则设置为x。因此,最初的问题(关于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:答案是关于65535.75...,所以xmax==65535。因此,如果我们从0检查xxmax,我们将不会有溢出问题。这也是我们的初始值的二进制搜索算法。

也意味着,我们不需要在这里使用二进制搜索算法,因为只检查65535个值就足够了。如果x==65535不是答案,我们必须停止并返回答案65536

如果我们需要不硬编码xmax的跨平台解决方案,我们可以使用任何bigint实现(GMP或任何更简单的解决方案)或实现更精确的乘法等操作。例如:如果我们需要将xy相乘,我们可以计算z=ULLONG_MAX/x,并将此值与y进行比较。如果z<y,我们不能将xy相乘而不溢出

你可以试着找到一个上限,然后从那里开始。

// 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;

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

快速回答:

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

这个上界开始

x = abs ((b) ^ (1/4))

从该值开始递减,一旦找到元素<=b,就完成了。

你甚至可以这样想:

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

看到这个

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

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

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

为什么?因为x^4+x^3+x^2+x+1在x趋于正无穷时是无界的。你的不等式不存在b。计算机科学是数学的一个子集。