【问题标题】:How to find largest sum of divsors of a number between 2 and N?如何找到2到N之间数字的最大除数和?
【发布时间】:2018-12-06 23:08:40
【问题描述】:

我有一道简单的数学题。我想在[2,N](不包括除数中的1和N)范围内找到一个除数之和最大的数字。例如,对于N = 100,2 到 100 之间除数之和最大的数字是 96,它的所有除数之和等于 155。

我编写了以下程序来显示该数字的除数之和,但无法弄清楚如何获得该数字本身。如何找到并打印该号码?

int main(int argc, char const *argv[])
{
    int N,
        sum,
        max=0;

    scanf("%d", &N);

    int i = 0,
        d = 0;
    for(i=2; i<=N; i++)
    {
        sum=0;
        for(d = 2; d < i; d++)
        {
            if(i % d == 0)
            {
                sum += d;
            }
        }

        if(sum > max)
        {
            max = sum;
        }

    }
    printf("%d\n", max);


    return 0;
}

【问题讨论】:

  • 能否请您添加一个数学示例来说明您的问题?我不明白它背后的数学任务。
  • 完成了,这个例子可以理解吗?
  • 谢谢,我明白了:1、2、3、4、6、8、12、16、24、32、48的总和为96
  • http://www.positiveintegers.org/96 中,除数还包括数字 1,因此您应该尝试在代码的第二个循环中从 1 开始以获得总和 156,但是 1 不会改变区间 [2,N] 的最大值。
  • 对不起!我忘了提到该算法不需要明确包含 N 和 1 作为除数

标签: c loops math arithmetic-expressions


【解决方案1】:

其他人已经很好地展示了如何保存和报告出现最大值的i

但我想补充一下 OP 的方法如何显着更快:迭代到 N 而不是 N 的平方根。这种方式大约快 square_root(N) 倍。 N 为 100 时没那么重要,但对于较大的则很重要。

#include <stdlib.h>
#include <stdio.h>

void print_maxsumdiv(int N, int mode) {
  unsigned long long loop_count = 0;
  int sum, max = 0;
  int max_i = 0;
  int i = 0, d = 0;
  for (i = 2; i <= N; i++) {
    sum = 0;

    if (mode) {
      // Iterate up to the just under the square root of `i`
      for (d = 2;  d < i/d; d++) {
        loop_count++;
        if (i % d == 0) {
          sum += d + i/d;  // Add both dividers
        }
      }
      if (d == i/d) {  // perfect square
        sum += d;
      }
    }
    else {
      // Iterate up `i`  (OP's original approach)
      for (d = 2;  d < i; d++) {
        loop_count++;
        if (i % d == 0) {
          sum += d;
        }
      }
    }

    if (sum > max) {
      max = sum;
      max_i = i;
    }

  }
  printf("i:%6d max:%9d (count:%12llu)\n", max_i, max, loop_count);
}

int main() {
  for (int mode = 0; mode < 2; mode++) {
    print_maxsumdiv(100, mode);
    print_maxsumdiv(10000, mode);
    //print_maxsumdiv(1000000, mode);
  }
  return 0;
}

输出

i:    96 max:      155 (count:        4851)
i:  9240 max:    25319 (count:    49985001)
i:    96 max:      155 (count:         480)
i:  9240 max:    25415 (count:      646800)

【讨论】:

    【解决方案2】:

    应该很容易。再引入一个变量valueForMax

    int N,
        sum,
        max=0,
        valueForMax = 0;
    

    并与max一起更新

        if(sum > max)
        {
            valueForMax = i;
            max = sum;
        }
    

    那你就可以了

    printf("best value %d, sum = %d\n", valueForMax, max);
    

    【讨论】:

      【解决方案3】:

      当您保存max 时,您只需将i 的副本保存在一个单独的变量中。


      这是一个工作程序:

      #include <stdio.h>
      
      int
      main(int argc, char const *argv[])
      {
          int N,
           sum,
           max = 0;
          int max_i = -1;
      
          printf("Enter N: ");
          fflush(stdout);
      
          scanf("%d", &N);
      
          int i = 0,
              d = 0;
      
          for (i = 2; i <= N; i++) {
              sum = 0;
              for (d = 2; d < i; d++) {
                  if (i % d == 0) {
                      sum += d;
                  }
              }
      
              if (sum > max) {
                  max = sum;
                  max_i = i;
              }
      
          }
      
          printf("MaxSum:%d Index:%d\n", max, max_i);
      
          return 0;
      }
      

      这是输出:

      MaxSum:155 Index:96
      

      【讨论】:

      • 等等,为什么 max i 的值为 -1?
      • 防止编译器发出“可能未初始化的值”警告。例如,没有它,如果N 是(例如)1max_i 将具有未初始化/不可预测的值,并且编译器将能够注意到这一点。因此,初始化为 any 值可以防止出现此警告,但是,使用 -1 会清楚地表明循环从未在运行时执行 [因为如果 max_i = i 曾经执行过,它永远不会是-1]。经过思考,也许0 会是更好的选择。
      猜你喜欢
      • 1970-01-01
      • 2011-03-22
      • 2012-01-06
      • 2016-04-11
      • 2018-08-22
      • 2016-02-07
      • 2020-10-31
      • 1970-01-01
      • 2011-10-31
      相关资源
      最近更新 更多