递归-C++的问题

problems with Recursion - C++

本文关键字:问题 -C++ 递归      更新时间:2023-10-16

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

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

例如,数字20有5个适当的除数:1、2、4、5、10,并且除数总和为:1+2+4+5+10=22。<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这样的数字,这给我带来了错误,有更好的方法吗,或者我在某个地方犯了错误。

--感谢您抽出时间

这里有一种递归方法来解决您的问题:

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));
}

您需要调用find_sum(N, N-1);才能找到N的除法器之和(由于严格的不等式,i必须小于给定的N)。

在您的情况下,它将是find_sum(20, 19);

例如,我的函数返回:

  • 71086用于N = 50000

  • 22用于N = 20

  • 0用于N = 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;
}

我试着用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函数是递归使用的,并传递代码中所示的参数。

希望能有所帮助。

我认为不应该使用递归。

相反,从1..N-1 开始循环

找到除数后,调整循环的结束值。例如,如果2是除数,那么你知道N/2也是除数。同样重要的是,你知道在这个范围内不可能有更多的除数。同样,如果3是除数,那么你知道N/3也是除数,你知道这个范围内不再有除数

根据这个概念,你可以显著减少大多数数字的循环次数。

类似于:

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来减少循环的数量。