Recursion的问题 - C ++

时间:2015-12-22 18:50:17

标签: c++ recursion

给定自然数n(1 <= n <= 500000),请输出所有适当除数的总和。

定义:自然数的适当除数是严格小于数的除数。

e.g。数字20有5个适当的除数:1,2,4,5,10,除数求和为:1 + 2 + 4 + 5 + 10 = 22。 &lt;&lt; - 这是我想要做的挑战,我正在使用递归

int find_sum(std::vector <int> nums,long int sum,int num_now,long int j)
{

if(j<nums[num_now])
{
    if(nums[num_now]%j==0)
    {
        sum=sum+j;
    }
    return find_sum(nums,sum,num_now,j+1);
}
else
{
 return sum;
}

}

sum是所有除数的总和,nums是我存储的数字的向量,num_now是向量中的当前成员,int j是1我用它来搜索分隔符,遗憾地使用这个我不能使用像500000这样的数字它给出& #39;我的错误,有没有更好的办法,或者我在某个地方犯了错误。

- 谢谢您的时间

4 个答案:

答案 0 :(得分:2)

这是解决问题的递归方法:

User.where(:_id => "one of your users").includes(:party).first

您需要致电int find_sum(int x, int i) { if(i == 0) return 0; if(x % i == 0) return i + find_sum(x, (i-1)); return find_sum(x, (i-1)); } 以查找N的分隔符总和(find_sum(N, N-1);必须小于给定的i,因为严格的不等式)。

在您的情况下,它将是N

e.g。我的函数返回:

  • find_sum(20, 19); 71086

  • N = 50000 22

  • N = 20 0

答案 1 :(得分:1)

我没有看到你需要使用递归来解决这个问题的原因。我宁愿采用更直观的方式来解决它。

long CalculateSumOfDivisors(int number)
{
    long sum = 0;
    for(int i=1; i<number; i++)
    {
        // If the remainder of num/i is zero
        // then i divides num. So we add it to the 
        // current sum. 
        if(number%i==0)
        {
            sum+=i;
        }
    }
    return sum;
}

此外,如果我们注意以下内容,我们可以编写更优的算法:

假设我们有一个数n和d是n的最大除数,它是1的最大除数。(显然,如果数n是素数,则存在任何这样的除数)。然后n的大除数是数字n / d。

基于此,我们可以制定更优化的算法。

long CalculateSumOfDivisors(int number)
{
    int smallestDivisor = FindSmallestDivisor(number);
    if(smallestDivisor==1) return 1;

    long sum = smallestDivisor;

    // Calculate the possible greatest divisor.
    int possibleGreatestDivisor = (int)floor(number/smallestDivisor); 

    for(int i=smallestDivisor+1; i<=possibleGreatestDivisor; i++)
    {
        if(number%i==0)
        {
            sum+=i;
        }
    }
    return sum;
}

int FindSmallestDivisor(int number)
{
    int smallestDivisor = 1;
    for(int i=2; i<number; i++)
    {
        if(number%i==0)
        {
            smallestDivisor = i;
            break;     
        } 
    }
    return smallestDivisor;
}

答案 2 :(得分:0)

我认为你不应该使用递归。

而是从1..N-1

循环开始

当您找到除数时,调整循环的结束值。例如,如果2是除数,那么你知道N / 2也是一个除数。同样重要的是你知道在这个范围内不会有更多的除数] N / 2:N [。同样,如果3是除数,那么你知道N / 3也是一个除数,你知道范围内没有更多的除数] N / 3:N [。

遵循这一概念,您可以显着减少大多数数字的循环次数。

类似的东西:

long find_sum(int num)
{
    long sum = 0;
    int max = num;
    int i = 1;
    while(i < max)
    {
        if(num % i == 0)
        {
            sum += i;        // Add i to the sum
            max = num / i;   // Decrement max for performance
            if (max != i && max != num)
            {
                sum += max;  // Add max when max isn't equal i
            }
        }
        i++;
    }
    return sum;
}

示例:

num = 10
sum = 0
i = 1 -> sum = 1, max = 10
i = 2 -> sum = 1+2+5, max = 5
i = 3 -> sum = 1+2+5, max = 5
i = 4 -> sum = 1+2+5, max = 5
i = 5 -> return 8 (1+2+5)

num = 64
sum = 0
i = 1 -> sum = 1, max = 64
i = 2 -> sum = 1+2+32, max = 32
i = 3 -> sum = 1+2+32, max = 32
i = 4 -> sum = 1+2+32+4+16, max = 16
i = 5 -> sum = 1+2+32+4+16, max = 16
i = 6 -> sum = 1+2+32+4+16, max = 16
i = 7 -> sum = 1+2+32+4+16, max = 16
i = 8 -> sum = 1+2+32+4+16+8, max = 8
i = 9 -> return (1+2+32+4+16+8)

每当找到新的除数时,通过更改max来保持循环次数。

答案 3 :(得分:0)

我尝试用main函数编写代码,要求用户给它想要得到的总和。这是代码,希望它有所帮助。

#include<iostream>

using namespace std;

int Sum(int min, int max, int &val, int &sum){
if(min >= max)
    return 0;

for ( ; min < max; min++){
    if ( val%min == 0){
        sum += min + val/min;
        return Sum(++min,val/min, val,sum);
    }
}
    return 0;
}

int main(){
    int s=1;
    int val;
    cout <<"Enter Val to sum:";
    cin >> val;
    Sum(2,val,val,s);
    cout <<"Sum is :"<<s<<endl;
    return 0;
}

这里Sum函数以递归方式使用并传递参数,如代码所示。

希望它有所帮助。