歡迎辭

歡迎來到“篤志以礪,決起而飛”!
如果您是第一次來到本站,建議訪問本站導讀以便更快地了解本站。
如果您喜歡本站,歡迎訂閱

 

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>