作者的话:若有朋友复制代码去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;
}