zoukankan      html  css  js  c++  java
  • pku 1142 Smith Number

    /*
    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;
    }
    
    
  • 相关阅读:
    浅谈树的重心
    倍增的奇妙用处
    KMP——从入门到不会打题
    万能的进制哈希
    浅谈扫描线算法的应用
    无需Flash录视频——HTML5中级进阶
    一个模仿微信群聊的H5页面
    关于建议
    前端技术学习线路
    Kurento安装与入门02——运行示例前的准备
  • 原文地址:https://www.cnblogs.com/ajeyone/p/1840637.html
Copyright © 2011-2022 走看看