C语言PAT刷题 - 1019 数字黑洞

作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答。
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故出现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。

一、题目描述
给定任一个各位数字不完全相同的 4 位正整数,如果我们先把 4 个数字按非递增排序,再按非递减排序,然后用第 1 个数字减第 2 个数字,将得到一个新的数字。一直重复这样做,我们很快会停在有“数字黑洞”之称的 6174,这个神奇的数字也叫 Kaprekar 常数。

例如,我们从6767开始,将得到

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
7641 - 1467 = 6174
… …
现给定任意 4 位正整数,请编写程序演示到达黑洞的过程。

输入格式:
输入给出一个 (0,104) 区间内的正整数 N。

输出格式:
如果 N 的 4 位数字全相等,则在一行内输出 N - N = 0000;否则将计算的每一步在一行内输出,直到 6174 作为差出现,输出格式见样例。注意每个数字按 4 位数格式输出。

输入样例 1:
6767
输出样例 1:
7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
输入样例 2:
2222
输出样例 2:
2222 - 2222 = 0000
二、解题思路
读题:

接收一个四位正整数(输入不足四位的在他前面补0,如输入12,看做0012),把它四个位置上的数字分别按降序和升序排列,得到两个四位数,将这两个数相减,得到新的数字。新的数字各位继续按降序和升序排列,继续相减,一直到差变成6174(注意:一定要差变成6174),程序终止。
额外要求
(1)程序要把中间的所有相减算式一行一个地输出在屏幕上。
(2)当接收的四位正整数四位均相等时,则在一行内输出 N - N = 0000(N为四位整数)。
(3)减法算式中所有的数都要表示成四位数(如12表示成0012)。
思路:
1.接收 (0,10^4) 区间内的正整数N,存放在变量n中;
2.调用Kaprekar函数实现想要的功能;
3.Kaprekar函数定义:
(1)设置循环,循环条件是n!=6174,只要满足这个条件(即n没有走到6174),循环就要继续;
(2)将接受到的四位正整数的四位数字分离,保存在num数组的四个元素中,随时可以使用;
(3)设置判断,当接收的四位正整数四位均相等时,则在一行内输出 N - N = 0000(N为四位整数)。
(4)重排序,将四位数字降序排列,并计算出n1(各位降序排列的四位数)的值,并打印减法算式的前半部分;
(5)n1的四位降序排列,存储在数组num中,所以只要将数组的各个元素倒序输出,得到的就是升序排列的四位数;
(6)计算出n2(各位升序排列的四位数)的值以及n1-n2的值,并打印减法算式的中间部分;
(7)将n1-n2的结果的四位进行分离,分别打印;
(8)设置if条件判断语句,如果这次减法算式得到的结果不为6174,则输出换行符,开始下一轮循环;如果是6174,则结束循环。
三、具体实现
0.标准C源程序框架

#include <stdio.h>
int main()
{
	return 0;
}

1.接收 (0,10^4) 区间内的正整数N,存放在变量n中;

    int n;
    scanf("%d", &n);

2.调用Kaprekar函数实现想要的功能;

    Kaprekar(n);

3.Kaprekar函数定义:
(1)设置循环,循环条件是n!=6174,只要满足这个条件(即n没有走到6174),循环就要继续;
(2)将接受到的四位正整数的四位数字分离,保存在num数组的四个元素中,随时可以使用;
(3)设置判断,当接收的四位正整数四位均相等时,则在一行内输出 N - N = 0000(N为四位整数)。
(4)重排序,将四位数字降序排列,并计算出n1(各位降序排列的四位数)的值,并打印减法算式的前半部分;
(5)n1的四位降序排列,存储在数组num中,所以只要将数组的各个元素倒序输出,得到的就是升序排列的四位数;
(6)计算出n2(各位升序排列的四位数)的值以及n1-n2的值,并打印减法算式的中间部分;
(7)将n1-n2的结果的四位进行分离,分别打印;
(8)设置if条件判断语句,如果这次减法算式得到的结果不为6174,则输出换行符,开始下一轮循环;如果是6174,则结束循环。

void Kaprekar(int n)
{
    int j = 0, k = 0;
    int num[4];//存储个位、十位、百位、千位
    int temp = 0;
    int n1, n2;
    //(1)设置循环,循环条件是n!=6174,只要满足这个条件(即n没有走到6174),循环就要继续;
    do{
    	//(2)将接受到的四位正整数的四位数字分离,保存在num数组的四个元素中,随时可以使用;
        n1 = n2 = 0;//由于每轮循环n1、n2不同,且这两个数每轮循环都需要进行累加,所以为了排除上一轮循环的n1、n2的干扰,每次循环开始前两个变量都要置0
        num[0] = (n % 10);
        num[1] = (n / 10 % 10);
        num[2] = (n / 100 % 10);
        num[3] = (n / 1000);
        //(3)设置判断,当接收的四位正整数四位均相等时,则在一行内输出 N - N = 0000(N为四位整数)。
        if(num[0]== num[1]&& num[0] == num[2]&& num[0] == num[3]) { printf("%d - %d = 0000", n,n); break; }
        //(4)重排序,将四位数字降序排列,并计算出n1(各位降序排列的四位数)的值,并打印减法算式的前半部分;
        for (j = 0; j < 3; j++)
        {
            for (k = 0; k < 3 - j; k++)//降序排列
            {
                if (num[k] < num[k + 1])
                {
                    temp = num[k];
                    num[k] = num[k + 1];
                    num[k + 1] = temp;
                }
            }
        }
        for (j = 0; j < 4; j++) { n1 = 10 * n1 + num[j]; }
        printf("%d%d%d%d - ", num[0], num[1], num[2], num[3]);
        //(5)n1的四位降序排列,存储在数组num中,所以只要将数组的各个元素倒序输出,得到的就是升序排列的四位数;
        //(6)计算出n2(各位升序排列的四位数)的值以及n1-n2的值,并打印减法算式的中间部分;
        for (j = 3; j >= 0; j--) { n2 = 10 * n2 + num[j]; }
        n = n1 - n2;
        printf("%d%d%d%d = ", num[3], num[2], num[1], num[0]);
        //(7)将n1-n2的结果的四位进行分离,分别打印;
        num[0] = (n % 10);
        num[1] = (n / 10 % 10);
        num[2] = (n / 100 % 10);
        num[3] = (n / 1000);
        printf("%d%d%d%d", num[3], num[2], num[1], num[0]);
        //(8)设置if条件判断语句,如果这次减法算式得到的结果不为6174,则输出换行符,开始下一轮循环;如果是6174,则结束循环。
        if (n != 6174)printf("\n");
        else break;
    } while (n != 6174);
}

四、测试数据
1.
输入:1(当输入数字是一位数,即减数前面有3个0时,会不会显示出来)
输出:
1000 - 0001 = 0999
9990 - 0999 = 8991
9981 - 1899 = 8082
8820 - 0288 = 8532
8532 - 2358 = 6174
2.
输入:21(当输入数字是两位数,即减数前面有2个0时,会不会显示出来)
输出:
2100 - 0012 = 2088
8820 - 0288 = 8532
8532 - 2358 = 6174
3.
输入:2222(输入四位相同的四位数时,会不会得到N - N = 0000)
输出:2222 - 2222 = 0000
4.
输入:6767(程序排序功能是否健全)
输出:
7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
5.
输入:1112(当差为三位数,即差前面要补0时,程序会不会补)
输出:
2111 - 1112 = 0999
9990 - 0999 = 8991
9981 - 1899 = 8082
8820 - 0288 = 8532
8532 - 2358 = 6174
6.
输入:6174(因为他要看我们到达数字黑洞的过程,要求我们的程序必须知道6174作为差出现才可以结束,所以即便给的就是数字黑洞,程序也要走一遍流程,展示数字黑洞到数字黑洞的过程,即函数的循环体至少执行一次)
输出:7641 - 1467 = 6174
五、全部代码

#include <stdio.h>
void Kaprekar(int n)
{
    int j = 0, k = 0;
    int num[4];//存储个位、十位、百位、千位
    int temp = 0;
    int n1, n2;
    do{
        n1 = n2 = 0;
        num[0] = (n % 10);
        num[1] = (n / 10 % 10);
        num[2] = (n / 100 % 10);
        num[3] = (n / 1000);
        if(num[0]== num[1]&& num[0] == num[2]&& num[0] == num[3]) { printf("%d - %d = 0000", n,n); break; }
        for (j = 0; j < 3; j++)
        {
            for (k = 0; k < 3 - j; k++)//降序排列
            {
                if (num[k] < num[k + 1])
                {
                    temp = num[k];
                    num[k] = num[k + 1];
                    num[k + 1] = temp;
                }
            }
        }
        for (j = 0; j < 4; j++) { n1 = 10 * n1 + num[j]; }
        printf("%d%d%d%d - ", num[0], num[1], num[2], num[3]);
        for (j = 3; j >= 0; j--) { n2 = 10 * n2 + num[j]; }
        n = n1 - n2;
        printf("%d%d%d%d = ", num[3], num[2], num[1], num[0]);
        num[0] = (n % 10);
        num[1] = (n / 10 % 10);
        num[2] = (n / 100 % 10);
        num[3] = (n / 1000);
        printf("%d%d%d%d", num[3], num[2], num[1], num[0]);
        if (n != 6174)printf("\n");
        else break;
    } while (n != 6174);
}
int main()
{
    //1.接收 (0,10^4) 区间内的正整数N,存放在变量n中;
    int n;
    scanf("%d", &n);
    //2.调用Kaprekar函数————重排序,用各位递减的整数n1-各位递增的整数n2,显示计算过程,若得到的值是0或6174则给出相应的输出,否则不断循环。
    Kaprekar(n);
    return 0;
}
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值