/* 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; }