题目链接:1019 数字黑洞 (20分)
给定任一个各位数字不完全相同的 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
题目分析:(已进行二次修改优化,最好跳过第一次看第二次的)
输入一个四位整数,用这个整数的每一位按照升序和降序分别得到两个数,让两个数做差,最后的差值肯定是6174,题目要求输出该计算过程。另外如果这个四位数每一位都相等,直接输出这个四位数减本身等于0000。
第一次做这个题目我有这几个思考的点:
1.我的四位数怎么实现升序降序的排列?
2.如果某次做差,差是个位数或者两位数或者三位数怎样做到还以四位输出?比如1000-0001要输出0999而不是999
3.如果获得的差是个位数或者二位数或者三位数该怎么把它恢复成四位数参与到下次做差运算中?
然后我第一次采用了笨办法做的,直白的翻译题目,虽然通过了。
第二次做这个题目:
显然第一次写出来的代码又臭又长,那就必须转换思想。其实不进行整型、数组、字符串之间的转换,只用一个字符串,遇到求差就临时转成整型求一下差,就能解决问题。
第一次题目代码:
#include <iostream>
#include <algorithm>
using namespace std;//进行每一位的升序,降序排列。
bool cmp(int a, int b){
return a > b;
}
int main(){
int div, a, b;//div是差,a是降序的减数,b升序的被减数
int num[4];//用来存储每一位的数的数组
string digit;
cin >> digit;//先当做字符串输入
if(digit.length()==1)//如果判断出来是个位数
digit[1] = digit[2] = digit[3] = '0';//就在后面补零
else if(digit.length()==2)//同理的补零操作
digit[2] = digit[3] = '0';
else if(digit.length()==3)//同理的补零操作
digit[3] = '0';
div = stoi(digit); //从字符串转换成数字
if(div==0){//如果发现是0就直接输出下面的字符串
cout << "0000 - 0000 = 0000";
return 0;
}
if(div==6174)//这个是本题目的第5个监测点,检查到输入的6174要输出下面的字符串
cout << "7641 - 1467 = 6174";
if(digit[0]==digit[1] && digit[1]==digit[2] && digit[2]==digit[3]){//判断每一位是否相等
cout << digit << " - " << digit << " = " << "0000";//如果每一位都相等就输这个字符串
return 0;
}
for(int i=0; i<4; i++)
num[i] = digit[i]-'0';//把字符串存储的每一位给到数组内
while(div != 6174){//什么时候检测到差变成了6174,什么时候停下循环
sort(num, num+4, cmp);//降序排序
cout << num[0] << num[1] << num[2] << num[3] << " - ";//把降序后的数输出
a = num[0]*1000+num[1]*100+num[2]*10+num[3];//算出来降序的数字
sort(num, num+4);
cout << num[0] << num[1] << num[2] << num[3] << " = ";//把升序后的数输出
b = num[0]*1000+num[1]*100+num[2]*10+num[3];//算出来升序的数字
div = a - b;//算出来差值
digit= to_string(div);//再把差值变成字符串
if(digit.length() == 1){//如果是个位数,就在前面补三个零
digit[4] = '\0';
digit[3] = digit[0];
digit[2] = '0';
digit[1] = '0';
digit[0] = '0';
}
else if(digit.length() == 2){//如果是两位数就在前面补两个零
digit[4] = '\0';
digit[3] = digit[1];
digit[2] = digit[0];
digit[1] = '0';
digit[0] = '0';
}
else if(digit.length() == 3){//如果是三位数就在前面补一个零
digit[4] = '\0';
digit[3] = digit[2];
digit[2] = digit[1];
digit[1] = digit[0];
digit[0] = '0';
}
cout<< digit[0] << digit[1] << digit[2] << digit[3] << endl;//然后每一位都输出出来
for(int i=0; i<4; i++)
num[i] = digit[i]-'0';//再把每一位都传给整型数组
}
return 0;
}
(第一次代码虽然又臭又长但是有一些整型和字符串相互转换的知识,所以之后会写一篇关于数字和字符串转换的博文,哈哈哈)
第二次代码:
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(char a, char b){//第一次忘记了这个sort不仅可以
return a > b;//比较数字也可以比较字符,这样就免除了字符和整型的切换
}
int main(){
string num;
int div;
cin >> num;
num.insert(0, 4-num.length(), '0');//string的成员函数,往num后面填0
if(num == "6174"){//一开始就是6174的情况
printf("7641 - 1467 = 6174");
return 0;
}
while(num!="6174"){
string a = num, b = num;//分别作为减数和被减数
sort(a.begin(), a.end(), cmp);//降序排序
sort(b.begin(), b.end());//升序排序
div = stoi(a) - stoi(b);//求商
num = to_string(div);//再把商转换到字符串
num.insert(0, 4-num.length(), '0');//把零补好
cout << a << " - " << b << " = " << num << endl;//按照格式输出
if(num == "0000") break;//如果碰到是零的情况就直接停止循环
}
return 0;
}
这里就巧妙地用到了string的成员函数insert,在这里讲一下:
string.insert():
用途:插入字符
例子:
str.insert(2, str2); //在str第2位插入str2
str.insert(2, "Hello World"); //在str第2位插入字符串
str.insert(2, str2, 3, 4); //把str2的3,4位插到str的第2位置
str.insert(2, "Hello World", 3); //在str的第2位插入中间字符串的第3位
str.insert(2, 10, '0'); //在str的第2位插入10个字符0
it = str.insert(str.begin()+5, '0');//在str的第5位插入字符0
str.insert (str.end(), 3, '0'); //在str的结尾插入3个字符0
bilibili:羊卓的杨