UVa Problem 10042 Smith Numbers (Smith 数)

// Smith Numbers (Smith 数)
// PC/UVa IDs: 110706/10042, Popularity: B, Success rate: average Level: 1
// Verdict: Accepted
// Submission Date: 2011-06-10
// UVa Run Time: 0.060s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// 对数进行素因子分解即可。因为所求数小于 10E9,若某数是合数,则其素因子至少有一个小于或等于
// sqrt(10E9),则可先计算 2 - sqrt(10E9) 之间的素数以备用。

#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>

using namespace std;

#define UPBOUND 31623	// ceil(sqrt(10E9))	

vector < int > prime;	// 存储 2 - ceil(sqrt(10E9)) 之间的素数,方便解题。

// 判断数 n 是否是素数。
bool is_prime(int n)
{
	if (n == 2)
		return true;

	if (n % 2 == 0)
		return false;
	
	for (int c = 3; c <= ceil(sqrt(n)); c += 2)
		if (n % c == 0)
			return false;
			
	return true;
}

// 预先产生 2 - ceil(sqrt(10E9)) 之间的素数。
void find_prime()
{
	prime.push_back(2);
	for (int c = 3; c < UPBOUND; c += 2)
		if (is_prime(c))
			prime.push_back(c);
}

// 计算数 number 的数位之和。
int digits_sum(int number)
{
	int sum = 0;
	while (number)
	{
		sum += (number % 10);
		number /= 10;
	}
	
	return sum;
}

void smith(int number)
{
	int current = number + 1;
	while (1)
	{
		// 如果是素数,不是 Smith 数。
		if (is_prime(current))
		{
			current++;
			continue;
		}
		
		// 计算数 current 的数位数字之和。
		int tmp = current;
		int sum = digits_sum(current), tsum = 0;
		
		// 计算数 current 的素因子之和。
		while (1)
		{
			int memo = tmp;
			for (int c = 0; c < prime.size(); c++)
				if (tmp % prime[c] == 0)
				{
					tmp /= prime[c];
					tsum += digits_sum(prime[c]);
					break;
				}
			
			// 若 tmp 为 1,表明找到了所有的素因子,若 tmp 未变化,则表明在
			// 2 - sqrt(10E9) 之间已经没有 tmp 的素因子存在,则 tmp 必定
			// 是一个素数。
			if (tmp == 1 || memo == tmp)
				break;
		}
		
		// 此时若 tmp 不为 1,则必定是素数,因为若是合数,在 2 - sqrt(10E9) 之间
		// 都没有它的素因子,这是不可能的,若这样,该数的素因子都大于sqrt(10E9),则
		// 该数必定大于 10E9,与题目条件不符合。
		if (tmp > 1)
			tsum += digits_sum(tmp);
		
		// 判断素因子和与数位和是否相等。
		if (tsum == sum)
		{
			cout << current << endl;
			break;
		}
		
		current++;
	}
}

int main(int ac, char *av[])
{
	int cases, number;
	
	find_prime();
	
	cin >> cases;
	while (cases--)
	{
		cin >> number;
		smith(number);
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值