当我获得第一个 n 数字的总和时,我正在尝试求解 n 的最接近值。 意思是如果我将总和设为60,那么我的 n 应该是10,因为前10个数字的总和是55,如果我包括11则总和将是66,超过我所需的总和。
int num=1, mysum = 0;
int givensum=60;
while (mysum < givensum) {
mysum += num;
num++;
}
cout<<num-1;
return 0;
我能想到解决这个问题的另一种方法是求解二次方程式
n(n+1) / 2 = givensum
并从中获取 n 。
有没有其他方法可以解决这个问题?
答案 0 :(得分:5)
我认为没有比解决quadratic equation更好的方法了。这很简单,
n*(n+1)/2 = sum
n^2 + n - sum*2 = 0
assumin ax^2 + bx + c = 0
a = 1, b = 1, c = -2*sum
因为我们不需要否定答案:
n = ( -b + sqrt(b^2 - 4ac) ) / 2a
这是实施:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int sum = 60;
int a = 1;
int b = 1;
int c = -sum*2;
double delta = b*b - 4*a*c;
if ( delta >= 0 ){
double x1 = -b + sqrt(delta);
//double x2 = -b - sqrt(delta); // we don't need the negative answer
x1 /= 2*a;
//x2 /= 2*a;
cout << x1 << endl;
}
else {
cout << "no result";
}
}
结果是浮点数,如果您希望 n 元素之和小于或等于输入和,则应使用floor
函数将其向下舍入。 / p>
考虑函数f(n) = n*(n+1)/2
,它产生第一个 n 整数的总和。此功能严格增加。因此,当f(n)
的值被赋予您时,您可以使用二进制搜索来查找 n :
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int sum = 61;
int low = 1, high = sum, mid;
while ( low < high ){
mid = ceil ( (low+high)/2.0 );
int s = mid*(mid+1)/2;
if ( s > sum ){
high = mid-1;
} else if ( s < sum ) {
low = mid;
} else {
low = mid;
break;
}
}
cout << low << endl;
}
答案 1 :(得分:1)
所以我们希望找到n
(n+1)*n/2 <= y < (n+2)*(n+1)/2
求解二次方程f(x)=y
,其中f(x)=(x+1)*x/2
可以使用浮点运算,然后将n
作为x
的整数部分。
但我们并不真正需要浮点数,因为我们只需要结果的整数部分,我们也可以使用Newton-Raphson迭代https://en.wikipedia.org/wiki/Newton%27s_method
f(x)
的衍生物是f'(x)=(x+(1/2))
。不是一个好的整数,但我们都可以乘以2,并像这样写循环:(这是Smalltalk,但这并不重要):
Integer>>invSumFloor
"Return the integer n such that (1 to: n) sum <= self < (1 to: n+1) sum"
| guess delta y2 |
y2 := self * 2.
guess := 1 bitShift: y2 highBit + 1 // 2.
[
delta := ((guess + 1) * guess - y2) // (guess * 2 + 1).
delta = 0 ]
whileFalse: [ guess := guess - delta ].
^guess - 1
所以我们这样迭代:
x(n+1) = x(n) - (2*f(x(n))-2*y)/(2*f'(x(n)))
但是我们不是采用精确的除法,而是使用//
,它是向下舍入到最接近的整数的商。
通常情况下,我们应该在最后阶段测试猜测是否被过高估计。
但是在这里,我们安排初步猜测是对结果的过高估计,但不要过高估计,以至于猜测总是会被高估。像这样我们可以在最后阶段简单地减去1。上面的实现使用粗略猜测第一位位置作为初始x
值。
然后我们可以检查前一万个自然整数的实现:
(1 to: 10000) allSatisfy: [:y |
| n sum |
n := y invSumFloor.
sum := (1 to: n) sum.
(sum <= y and: [y < (sum + n + 1)])].
回答true
Smalltalk的优点是你可以尝试这样的事情:
80 factorial invSumFloor.
得到类似的东西:
378337037695924775539900121166451777161332730835021256527654
你在这里看到Newton Raphson迅速融合(上例中有7次迭代)。这与最初的幼稚迭代非常不同。
答案 2 :(得分:0)
代码突破while
后,mysum
成为最接近givensum
的总和。对于您给出的示例,while
循环执行因为55 is less than 60
,并且mysum
变为66而num
在最后一次循环执行之前变为12停止。完成此步骤后,由于66 is not less than 60
,while
不会再次执行。因此,您应该mysum
减少num-2
。
cout<<num-2;