问题描述:
已知:若一个合数的质因数分解式逐位相加之和等于其本身逐位相加之和,则称这个数为Smith数。譬如:4937775 = 3*5*5*65837,而3+5+5+6+5+8+3+7 = 42,4+9+3+7+7+7+5 = 42,所以4937775是Smith数
求:给定一个正整数N,求大于N的最小Smith数
输入:若干个case,每个case一行代表正整数N,输入0表示结束
输出:大于N的最小Smith数
Sample Input:
4937774
0
Sample Output:
4937775
思路:
本题的关键是质因数分解
首先有如下性质:
- 任意合数都可被分解为几个质因数的乘积
- 给定合数的质因数分解表达式唯一
根据上述性质,我们的质因数分解思路如下:
设被分解合数为N,则分解步骤如下:
- 初始状态,M = 2
- 用M试除N,若能整除,说明M为N的质因数,则更新N = N / M,M不变;若不能整除,则N不变,M++
上述方法蕴涵两个特性:
- 被当前M整除的N其所有质因数均大于等于M。譬如:N若能被5整除,则其所有质因数均大于等于5,即其不可能再被2或3整除
- 不需要判断当前M是否为素数,因为若为合数则必然不能整除。证明如下:假设M当前为合数,且M的一个质因数为P,则若N能被M整除则必然能被P整除,这与特性1矛盾
代码:
#include <stdio.h>
#include <math.h>
void get_sum(long n, int * sum){ //逐位求和
while(n != 0){
*sum += n%10;
n /= 10;
}
}
int main(){
int sum1, sum2;
long ceil, n, nn, m;
int cnt;
while(1){
scanf("%ld", &ceil);
if(ceil == 0) break;
for(nn = ceil+1; ; nn++){
sum1 = sum2 = cnt = 0;
get_sum(nn, &sum1);
n = nn; //nn固定保存原N值,n用于整除后更新N值
m = 2;
while(m <= sqrt(n)){
if(n%m == 0){
cnt++; //cnt记录质因数个数,即标识了是否为素数
n = n/m;
get_sum(m, &sum2);
}
else m++;
}
get_sum(n, &sum2);
if(sum1 == sum2 && cnt != 0){
printf("%ld\n", nn);
break;
}
}
}
return 0;
}