/*
Author: JackWang
Date: 01-10-10 20:20
Description:
求Smith数,Smith数的所有因数的数字之和等于自己的数字之和
例子:
本题中,质数不算Smith数
解题思路:
因为要因式分解,所以要算质数,而且要存储从2开始的一些质数,方便分解计算。
算质数用筛法计算。
质数要算多少是一个问题,题目保证最大的数是100,000,000以内,在32位int之内。
但是用筛法算100,000,000内的所有质数是耗时很长的,因此只能算一部分。其余部分直接用简单判别法判断。
简单判别法:判断它是否能整除小于等于它平方根的数,如果能整除,就不是质数,如果都不能整除则它是质数。
因此,计算100,000,000的因数只需要sqrt(10,000,000) = 10,000以内的数即可,因此筛法计算10,000个质数即可。
*/
#include <iostream>
#include <cmath>
using namespace std;
const int N = 1000000; // 筛法中的最大判断数量
const int P = 78498; // 在N的范围内质数的数量
const int MAX_PRIME = 999983; // 在N的范围内最大的质数
char isPrime[N]; // 筛法中是否是质数的布尔向量,0为质数1为合数
int primeNumbers[P]; // 按顺序从小到大的N范围内的所有质数
int primeDigitSum[P]; // 与所有质数相对应的数量和,primeNumbers[i]的数量和 = primeDigitSum[i]
// 计算一个正整数的各个数字之和。
int sumDigits(int n) {
int sum = 0;
while (n > 0) {
sum += n % 10;
n /= 10;
}
return sum;
}
// 初始化:筛法计算质数;并计算这些质数的数字和
void calcprime() {
// 筛法计算质数
for (int i = 2; i < N; ++i) {
if (isPrime[i] == 0) {
for (int j = i + i; j < N; j += i) {
isPrime[j] = 1;
}
}
}
int count = 0; // 质数的计数
for (int i = 2; i < N; ++i) {
if (isPrime[i] == 0) {
primeNumbers[count] = i;
primeDigitSum[count] = sumDigits(i); // 预保存质数的数字和,减少Smith数判断时的计算量
++count;
}
}
}
// 判断一个数是否是质数
bool isPrimeNumber(int n) {
if (n < 2) {
return false;
}
// 如果小于N,直接用筛法的结果就可以判断。
if (n < N) {
return isPrime[n] == 0;
}
// 如果大于等于N,则用简单判别法
int max = (int)sqrt(n) + 1;
for (int i = 0; i < P && primeNumbers[i] <= max; ++i) {
if (n % primeNumbers[i] == 0) {
return false;
}
}
return true;
}
// 判断一个数是否是Smith数,要在N范围内才有效。
bool isSmithNumber(int n) {
if (isPrimeNumber(n)) {
return false;
}
int nSum = sumDigits(n);
int pSum = 0;
// 分解因子,分解过程中直接计算数字和
int i;
for (i = 0; i < P && primeNumbers[i] <= n; ++i) {
// 这个循环里计算小于等于MAX_PRIME的因子
while (n % primeNumbers[i] == 0) {
n /= primeNumbers[i];
pSum += primeDigitSum[i];
}
}
// 若此时n>1,则表明n不是MAX_PRIME以内因子产生的合数,
// 又因为MAX_PRIME以内质数相乘得到的合数一定在10,000,000范围内,
// 所以n一定是质数,要计算这个因子的数字和
if (n > 1) {
pSum += sumDigits(n);
}
return pSum == nSum;
}
int main() {
calcprime();
int n;
while (cin >> n, n > 0) {
while (!isSmithNumber(++n));
cout << n << endl;
}
return 0;
}