您的位置:首页 > 编程语言 > C语言/C++

Prime Palindromes( 素数回文) C++实现

2010-04-15 18:49 316 查看
Prime Palindromes

Time limit: 15sec. Submitted: 10679

Memory limit: 32M Accepted: 1958

Source: USACO Gateway

The number 151 is a prime palindrome because it is both a prime number and a palindrome (it is the same number when read forward as backward). Write a program that finds all prime palindromes in the range of two supplied numbers a and b (5 <= a < b <= 1000,000,000); both a and b are considered to be within the range .

Input

Line 1: Two integers, a and b

Output

The list of palindromic primes in numerical order, one per line.

Sample Input

5 500

Sample Output

5

7

11

101

131

151

181

191

313

353

373

383

开始拿到题目的时候,一看。恩!挺简单的,于是边哗啦啦地开始coding。

很快,代码写好了。

首先我们先判断以下一个数是不是素数,这个就暂时想到朴素素数法了。

bool is_primer(const unsigned int number)

28 {

29 int i;

30 unsigned int sqrt_num;

31 sqrt_num = sqrt(number + 1);

32 for(i = 3; i <= sqrt_num; i += 2)

33 {

34 if((number % i) == 0)

35 return false;

36 }

37 return true;

38 }

接下来就是该写palindromele了, 自己也没有多考虑,就是按正常的方法直接把函数写完,如下所示:

bool is_palindrome(const unsigned int number)

41 {

42 int button , top, middle;

43 unsigned int temp = number;

44 button = top = 0;

45 int i = 0;

46 int array[11];

47 while(1)

48 {

49 array[i] = temp % 10;

50 temp = temp /10;

51 if(temp == 0)

52 break;

53 i++;

54 }

55 top = i;

56 if(top % 2 != 0)

57 {

58 if(number == 11)

59 return true;

60

61 return false;

62 }

63 middle = top/2;

64 for(i = 0; (i <= middle)&& (top >= button); i++)

65 {

66 if(array[button] == array[top])

67 {

68 button++;

69 top--;

70 }

71 else

72 return false;

73 }

74 return true;

75 }

int main(void)

8 {

9 unsigned int min_bounder, max_bounder;

10 cin >> min_bounder >> max_bounder;

11

12 unsigned int i;

13

14 for(i = min_bounder; i < max_bounder; i++)

15 {

16 if((i % 2) != 0)

17 {

18 if(is_primer(i)&& is_palindrome(i))

19 {

20 cout << i << endl;

21 }

22 }

23 }

24

25 }

哈哈,大功告成! 等等....还没有Submit呢! 提交一看,惨了Time Limit Exceed!

到这一步,终于知道了,程序没有自己想象中的那么简单。

考虑了一下,我们知道,回文的判断应该比素数的判断要快,而且要比素数判断简单。所以应该先判断完了是不是回文,再判断

其是否为素数,这样速度回大有提高。于是改变一下回文判断与素数判断的先后顺序。

if( is_palindrome(i)&&is_primer(i))

提交,结果还是超时!

这回好像的想想办法了。可能是素数的判断算法效率太低了,还有可能是回文的判断效率低。于是我先来看看回文判断有没有可以提高的地方

想像一下1000,000,000。 这么大的数, 如果是按照上面的办法直接找回文的话。

循环for(i = min_bounder; i < max_bounder; i++)一遍就得 1000,000,000趟。可想而知,暂且不讨论素数判断问题,光是这个判断就

足以超时了。

再仔细深入研究了一下, 我们可能会很容易发现1000,000,000的回文最大为 999,999,999

而此处,由于是回文。我们只需要前半部分就可以了,所以我们可以把循环缩小为10000就可以了,比如说

1230321这个数,我们仅仅需要得到前面的半部分123就行了。

想到这里,算法也就已经出来了。同时我们还应该注意到一个问题,这个问题也可已很快地提高程序执行的速度

那就是偶数偶数位回文都不是素数,举个例子吧:

1551 可以被11整除, 153351也可以被11整除, 同理, 偶数位的回文都可以被11整除。

于是程序又可以得到了进一步的简化, 运行速度上也可以得到了很大的提高。

把回文函数修改一下如下所示:

#include <iostream>

#include <cmath>

using namespace std;

bool is_primer(const unsigned int number);

bool is_palindrome(const unsigned int min_bound, const unsigned int max_bound);

int power(const int a, const int n);

int reverse_num(const int number , unsigned int &total, int &reverse);

int main(void)

{

unsigned int min_bounder, max_bounder;

cin >> min_bounder >> max_bounder;

is_palindrome(min_bounder, max_bounder);

return 0;

}

/*判断是否为素数*/

bool is_primer(const unsigned int number)

{

int i;

int sqrt_num;

sqrt_num = sqrt(number);

for(i = 3; i <= sqrt_num; i += 2)

{

if((number % i) == 0)

return false;

}

return true;

}

/*获取回文的函数*/

bool is_palindrome(const unsigned int min_bound, const unsigned int max_bound)

{

int array[] = {5 , 7, 11};

int log_n_max = log(max_bound)/log(10);

int log_n_min = log(min_bound)/log(10);

int reverse = 0;

log_n_max /= 2;

log_n_min /= 2;

int middle_max = power(10, log_n_max);

int middle_min = power(10, (log_n_min-1));

unsigned int result = 0 , temp = 0;

if(min_bound <= 11 )

{

for( int i = 0 ; i < 3 ; ++i )

{

if( min_bound <= (unsigned)array[i] )

{

cout << array[i] << endl ;

}

}

}

int i , j , n = 0;

for(i = middle_min; i < middle_max; i++)

{

n = reverse_num(i, result, reverse);

temp = result;

if(reverse % 2 != 0)

{

/*这里我们只考虑奇数位数的回文, 这个循环实现如 12 将得到 12021 12121.....12921 */

for(j = 0; j < 10; j++)

{

temp = temp*10 + j*power(10, n);

temp = temp + reverse;

if(temp >= min_bound && temp < max_bound)

{

if(is_primer(temp))

{

cout << temp <<endl;

}

}

else

continue;

temp = result;

}

}

}

return true;

}

/*a 的 n 次幂*/

int power(const int a, const int n)

{

unsigned int temp = 1;

int i = 0;

for(i =0; i < n; i++)

{

temp *= a;

}

return temp;

}

/*把 number reverse 一下, 如123 --> 321 */

int reverse_num(const int number , unsigned int &total, int &reverse)

{

int temp = number , result = 0;

int array;

total = number;

int i = 1;

while(1)

{

array = temp % 10;

temp /= 10;

result = result * 10 + array;

total *= 10;

if(temp == 0)

break;

i++;

}

reverse = result;

return i;

}

实现到这一步之后,可以进行提交了,submit一下,OK。成功了。这里没有使用更好的素数判断算法,也没有这个必要了。15secs的时间足够了,

提交时,刚刚好消耗了0.45s的时间。

Proid Subtime Judgestatus Runtime Memory Language Code Length

1004 2010-04-15 18:02:13 Accepted 0.45 s 1248 K C++ 2581 B

后来我有和之前的程序对比了以下运行5 1000 000 000

前面的算法实现运行完总共需要的时间要好几分钟,结果还没运行完。这个时间上的差距确实很大很大。这里仅仅做了一个小小的优化而已。

其实这里还有很大的提高空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: