欢迎辞

欢迎来到“笃志以砺,决起而飞”!
如果您是第一次来到本站,建议访问本站导读以便更快地了解本站。
如果您喜欢本站,欢迎订阅

 

2012 年五月
« 四  
 123456
78910111213
14151617181920
21222324252627
28293031 

USACO Prime Palindromes (pprime)

这个程序是哈尔滨工业大学的一道作业题,有一位朋友昨晚让我看了这道题目,我发现这道题目还真不是那么简单。学校对刚刚学完数组的大一同学出此题目是否欠妥呢?

现在先看看题目。

Prime Palindromes

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 <= 100,000,000); both a and b are considered to be within the range .
PROGRAM NAME: pprime
INPUT FORMAT
Line 1:    Two integers, a and b
SAMPLE INPUT (file pprime.in)
5 500
OUTPUT FORMAT
The list of palindromic primes in numerical order, one per line.
SAMPLE OUTPUT (file pprime.out)
5

7

11

101

131

151

181

191

313

353

373

383

这道题目表面上来看比较简单,因为是很基础的算法——求素数和回文数。我先写了一个用循环求余法求素数和检验是否回文的函数,循环查找符合条件的数。

结果不出所料,显然超时。我需要对它进行优化。

所谓优化,无非是三点思路:减少判断是否素数的时间;减少判断是否回文的时间;减少被选数的数量,提高数的精确性。

判断回文并没有什么好优化的地方。就是把前后对称的每位对比一下,防止重复对比即可。

那么判断素数呢?

首先,我们考虑是否可以用筛法求素数。筛法求素数是先把所有的数保存在一起,然后去掉不符合要求的数。每次他找到一个素数,就把这个素数的所有倍数均删除,最后留下的就是需要的素数。

但是这种算法在本题是行不通的,因为数据范围高达 1,000,000,000,如果我们使用筛法,占用内存太大,然而这道题目要求的内存不超过 32MB。

所以我们继续优化求余法。首先,所有的偶数都可以排除(除2以外);其次,所有偶数位的数都可以排除。因为这样的数的奇数位和偶数位之和可以被11整除,这样的数一定可以被11整除,因此不可能是素数;另外,开头是0、2、4、5、6、8的可以排除,因为这样的回文数一定不是素数。

最后,还可以使用筛法的思路优化素数算法。因为要检查所有的数,对于大数的运算量过大;考虑下面的想法:如果一个数不能整除比他小的所有的素数,那么他一定是素数。原因是一个合数总能被分解为好多素数的积;如果每个质数都不能整除,那么也肯定不会有合数可以整除。

基于上述思路,再结合在求余法中广为应用的优化:只需要判断sqrt(该数)之前是否可以被整除,我们就可以确定,对于小于等于1,000,000,000 的数,只需要保存 10000 之前的素数,然后使用这些质数就可以校验所有的数是否是素数。

那么如何减少数的范围呢?根据偶数位的数一定不成立、开头结尾不能是0、2、4、5、6、8的要求,可以不穷举所有数,直接使用循环生成回文数表。而且,只需要循环数的一半,就可以生成对应的回文数表。

所以最后,我用的算法是这样的:先直接算出10000内的质数表,生成所有小于取值范围并且剪枝过的回文数表,并用质数表去验证是否为质数。

程序如下(最长用时 0.02 秒)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
ID:cxj6661
PROG:pprime
LANG:C++
*/
 
/*
 * Prime Palindromes
 * By Ceeji
 * Type: Normal
 * For: Friend(Liuhaodong)
 * Date: 2010-10-30
 * Under CC 3.0
 */
 
#include <iostream>
#include <cmath>
#include <string>
#include <fstream>
#include <cstring>
 
 
using namespace std;
 
const int maxl = 10, maxp = 10000;
const char *inf_name = "pprime.in";
const char *ouf_name = "pprime.out";
 
int primes[maxp];
bool isp[maxp];
int plen;
 
bool prime(int i)
{
	if (i == 1)
		return false;
	if (i == 2 || i == 3)
		return true;
	if (i % 2 == 0)
		return false;
	int m = (int)sqrt((float)i);
	if (m > i - 1)
		m = i - 1;
	for (int j = 3; j < m + 1; j += 2)
	{
		if (i % j == 0)
			return false;
	}
	return true;
}
 
 
bool prime2(int i)
{
	if (i < 10001)
	{
		return isp[i];
	}
	if (i == 2 || i == 3)
		return true;
	if (i % 2 == 0)
		return false;
	int m = (int)sqrt((float)i);
	for (int j = 0; j < plen; ++j)
	{
		if(primes[j] > m + 1)
			break;
		if (i % primes[j] == 0)
			return false;
	}
	return true;
}
 
bool palindrome(int i)
{
	char ch[10];
	sprintf(ch, "%d", i);
	int l = strlen(ch);
	for (int p = 0; p < l / 2 + 1; ++p)
	{
		if (ch[p] != ch[l - p - 1])
			return false;
	}
	return true;
}
 
int main(void)
{
	ifstream fin(inf_name);
	ofstream fou(ouf_name);
	int a, b;
	fin >> a >> b;
	/* Find primes which are not bigger than 10000; this will accelerate the prime2 function to check number from 0 to 1,000,000,000. */
	for (int i = 1; i <= 10000; ++i)
	{
		if (prime(i))
		{
			primes[plen++] = i;
			isp[i] = true;
		}
		else
			isp[i] = false;
	}
	for (int i = a; i < 100; ++i)
	{
		if (i >= a && i <= b && palindrome(i) && prime2(i))
		{
			fou << i << endl;
		}
	}
	int now = 0;
	/* Now check for the palindrome with width of 3 */
	for (int i = 1; i < 10; i += 2)
		for (int j = 0; j < 10; ++j)
		{
			if (i == 5)
				continue;
			now = i * 100 + j * 10 + i;
			if (now < a)
				continue;
			if (now > b)
			{
				fou << flush;
				return 0;
			}
			if (prime2(now))
				fou << now << endl;
		}
	/* Now check for the palindrome with width of 5 */
	for (int i = 1; i < 10; i += 2)
	{
		if (i == 5)
			continue;
		for (int j = 0; j < 10; ++j)
			for (int k = 0; k < 10; ++k)
			{
				now = i * 10000 + j * 1000 + k * 100 + j * 10 + i;
				if (now < a)
					continue;
				if (now > b)
				{
					fou << flush;
					return 0;
				}
				if (prime2(now))
					fou << now << endl;
			}
	}
	/* Now check for the palindrome with width of 7 */
	for (int i = 1; i < 10; i += 2)
	{
		if (i == 5)
			continue;
		for (int j = 0; j < 10; ++j)
			for (int k = 0; k < 10; ++k)
				for (int l = 0; l < 10; ++l)
				{
					now = i * 1000000 + j * 100000 + k * 10000 + l * 1000 + k * 100 + j * 10 + i;
					if (now < a)
						continue;
					if (now > b)
					{
						fou << flush;
						return 0;
					}
					if (prime2(now))
						fou << now << endl;
			}
	}
	/* Now check for the palindrome with width of 9 */
	for (int i = 1; i < 10; i += 2)
	{
		if (i == 5)
			continue;
		for (int j = 0; j < 10; ++j)
			for (int k = 0; k < 10; ++k)
				for (int l = 0; l < 10; ++l)
					for (int m = 0; m < 10; ++m)
					{
						now = i * 100000000 + j * 10000000 + k * 1000000 + l * 100000 + m * 10000 + l * 1000 + k * 100 + j * 10 + i;
						if (now < a)
							continue;
						if (now > b)
						{
							fou << flush;
							return 0;
						}
						if (prime2(now))
							fou << now << endl;
			}
	}
	fou << flush;
	return 0;
}

您也许喜欢

  1. USACO 1.3 Prime Cryptarithm (crypt1)
  2. USACO 1.3 Calf Flac(calfflac)
  3. USACO 1.2 Dual Palindromes 双重回文数 程序
  4. C# : 新台幣轉換為金額大寫(轉國字大寫)
  5. USACO 1.1 beads 程序
  6. USACO 1.2 Name That Number(namenum) 程序

5 comments to USACO Prime Palindromes (pprime)

Leave a Reply

  

  

  

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>