由求完数的经典OJ题引发的思考

XD-OJ T30

标题: 完数
类别: 时间限制: 2 S
内存限制: 10000 Kb
问题描述: 请写一个程序,给出指定整数范围[a,b]内的所有完数,0 < a < b < 10000。
一个数如果恰好等于除它本身外的所有因子之和,这个数就称为”完数”。
例如6是完数,因为6=1+2+3 输入说明 输入为两个整数a和b,a和b之间用空格分隔
输出说明 输出[a,b]内的所有完数,每个数字占一行
输入样例 1 10
输出样例 6

简单的思路:

在[a,b]中取得一个数,求这个数字的所有因数,相加,之后与原数字比较,如果相等,原数字即为完数。

遍历[a,b]的所有数字,重复以上操作。

起初的想法是用数组来做,把每个因数保存到数组c[n]当中,然后对c[n]求和,再将完数储存到另一个数组当中,最后遍历输出另一个数组d[n]

第一次提交的代码

#include <stdio.h>

int main() {
    int a, b, c[10000], d[10000], i, n, g, k, l, sum;
    n = 1;
    k = 1;
    sum = 0;
    scanf("%d %d", &a, &b);
    c[0] = 0;
    while (1) { //对一个数b求因数,将每个因数放到数组里
        for (i = 1; i <= b - 1; i++)
            if (b % i == 0) {
                c[n] = i;
                n++;
            };
        for (g = 1; g <= n; g++) {
            sum = sum + c[g];
        }
        //判断b是否是完数,如果是,把这个值赋给数组dn中的一项
        if (sum == b) {
            d[k] = sum;
            k++;
        }
        sum = 0;
        b = b - 1;
        if (b <= a)
            break;
    }
    for (l = 1; l < k; l++) {
        printf("%d", d[l]);
    }
    return 0;
}

然而并没有预期的输出,这是为什么呢怎么会事呢

删除循环结构,发现这种思路判断一个数字是可行的,套上循环就错误。

具体而言是无输出结果,或者运行时错误。百思不得其解的我询问了某个大佬学长。

他给出的建议是

Robotxm

每次循环的时候sum置零,甚至你可以删掉数组c,计算因数的循环里直接给sum加

我好像想到了什么。

快看14行和16行,这里有两个计数的变量,还有一个sum变量。

先按照学长的建议,在程序循环内的最后一行加上

sum=0;

但是事情远没有这么简单

在进行下一次循环时,初始化sum=0确实没错,但是这个时候的n,是从上次循环接续下来的,比如说上一次循环有7个因数,那么结束循环时n=8,再赋值,假设有10个因数那就是从c[8]赋到从c[17]

再次求和时,g是从1开始的,也就是说,是从c[1]一直加到c[18],为什么是c[18]呢?

接着上边的例子,原因是求因数的循环结束之后,n++使得n=18,那也就相当于从n=1一直求和到n=18,求和的数字不仅仅是对这个数字的因数,还包括上个数字的因数。

好了,明白了症结,那我们开始改。

首先为了计数时存放因数的数组总是便于求和,我们数组编号总是从1开始每次存放因数的数组总是从c[1]到c[n]

其次,在求和时,我们要加所有的因数,不能多加,也不能少加,在上边的求因数结束以后,n++,即n比因数的个数要多1。所以我们求和时,求到

q=n-1

即可。

改好了贴成品

#include <stdio.h>

int main() {
    int a, b,c[10000],d[10000], i, n, g, k, l, sum;
    n = 1;
    k = 1;
    sum = 0;
    c[0]=0;
    scanf("%d %d",&a,&b);
    for(;b>=a;b--) { //对一个数b求因数,将每个因数放到数组里
        for (i = 1; i <= b-1 ; i++) {
            if (b % i == 0) {
                c[n] = i;
                n++;
            }
        }
        for (g = 1; g <n; g++) {
            sum = sum + c[g];
        }
        //判断b是否是完数,如果是,把这个值赋给数组dn中的一项
         if (sum == b) {
             d[k] = sum;
             k++;
         }
         sum = 0;
         g=1;
         n=1;
         }
     for (l = 1; l < k; l++) {
         printf("%d\n", d[l]);
     }
    return 0;
    }


还有第二种去掉了c[n]的版本

    #include<stdio.h>
    int main()
    {
        int i, j, s, a,b;  /*变量i控制选定数范围,j控制除数范围,s记录累加因子之和*/
        scanf("%d %d", &a,&b);  /* n的值由键盘输入*/
        for( i=a; i<=b; i++ )
        {
            s=0;  /*保证每次循环时s的初值为0*/
            for( j=1; j<i; j++ )
            {
                if(i%j == 0)  /*判断j是否为i的因子*/
                    s += j;
            }
            if(s == i)  /*判断因子这和是否和原数相等*/
                printf("%d\n", i);
        }
        return 0;
    }

嗯,每次循环之后变量归位。

你是不是想到了函数的调用?(形参)

或许还能有第三个版本。

To be continue;

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇