想必搜这个问题的同学都知道Smith数的概念,这里就不再赘述了,如果不清楚可以百度查一下。
然后就是源代码将在文章最后给出,注释很详细,这里就不解释了,直接看代码就可以了。
最后的最后博主想说的是,我在搜索有关Smith数资料的时候,发现了很多“错误的代码”,为什么要加双引号呢,因为这个问题通常是课本上或者别的什么地方的题,这些错误的代码都是面向测试样例编程,在课本上给的测试样例中,代码能够通过,但是换一个测试样例,就很可能会出错。如果你在别的地方看到Smith数问题的源代码,并且你是真的想学会这个算法
请测试它!!
最简单的测试,输入18(随便给的测试例子),如果给出的最小Smith数是22,那就说明这个代码是对的
22 = 2 * 11, 2 + 2 = 4, 2 + 1 + 1 = 4
可能你在别的地方看到的测试样例都是4937774,所以测试别的数据很重要。
源代码
#include <stdio.h>
//一个简单的求和函数,可以将数字分隔开然后进行求和
int add(int n){
int sum = 0;
while(n){
sum += n%10;
n /= 10;
}
return sum;
}
//判断是否为Smith数
//在这个函数中也同时添加了判断质数的代码,将其整合在了一起
bool smith(int n) {
//设置一个数组来存放质因数
int a[10000] = {0};
int i = 2;
int temp = n;
int index = 0;
int sum1 = 0;//sum1存放质因数分解的和
//注意这里有等号,也就是说,至少会有一个数字,也就是它本身会存入a数组中,为后续判断做了铺垫
while (i <= temp) {
//从小到大开始算质因数
//不断的除以2,直到不能整除,然后i++开始除以3...以此类推
if (temp%i == 0) {
a[index] = i;
index++;
temp /= i;
i = 2;
}
else i++;
}
//也就是说,该数为质数,不满足Smith数必须是合数的条件,直接返回false进行下一个数的判断
if(a[1] == 0) return false;
//该数不为质数,也就是合数,满足了Smith数最基本的条件,然后看质因数和与各个位数之和是否相等
else{
//这里很巧妙的解决了测试样例中4937775 = 3*5*5*65837中65837的分解
//如果a数组(存放质因数的数组)中有非一位数的数,则须对数字继续分解
for (int i = 0; a[i]!=0; i++){
a[i] = add(a[i]);
sum1 += a[i];
}
//sum2中存放数字各个位数的和
int sum2 = add(n);
//如果和相等,则说明该数就为Smith数,返回true,最后在主函数中打印
if (sum1 == sum2)return true;
else return false;
}
}
int main(){
int n;
int i = 0;
scanf("%d", &n);//输入一个数
//从n+1开始判断是否为Smith数
for (i = n+1; ; i++){
//当smith函数返回值为true时打印i
if(smith(i)){
printf("%d\n", i);
//打印完后break退出循环即可
break;
}
}
return 0;
}
这里smith函数是返回bool类型的,准确的说C语言是没有bool类型的,所以这里是cpp文件,如果要用C语言来完成,则将返回值改成int类型返回一个标记即可。
当然,如果你要是应付作业的话,该程序可帮不了你,因为题目要求输入0作为结束符。这个代码只能帮你找出Smith数,如果要完成题目就还需要动动你聪明的脑袋瓜小小的改进一下该程序。
最后的最后:博主发现一个问题,在学习算法时,简单的算法老师随便一讲就学会了,稍微难一点的学校的老师又很难给学生讲明白,需要自己下去学习,找资料的同时会遇到形形色色的代码,作为一名coder,需要抱着求真的心态去检验代码,而不是简简单单的crtl c+crtl v。正所谓实践是检验真理的唯一标准。
如有不足,欢迎各位大佬指正。