1. 程式人生 > >NEFU 2 - 猜想 - [篩法求素數]

NEFU 2 - 猜想 - [篩法求素數]

script 教學 鏈接 ger cst 科學 mat 表示 檢測

題目鏈接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=2

Time Limit:3000ms  Memory Limit:65536K

Description

哥德巴赫(Goldbach ]C.,1690.3.18~1764.11.20)是德國數學家;出生於格奧尼格斯別爾格(現名加裏寧城);曾在英國牛津大學學習;原學法學,由於在歐洲各國訪問期間結識了貝努利家族,所以對數學研究產生了興趣;曾擔任中學教師。1725年,到了俄國,同年被選為彼得堡科學院院士;1725年~1740年擔任彼得堡科學院會議秘書;1742年,移居莫斯科,並在俄國外交部任職。
1742年,哥德巴赫在教學中發現,每個不小於6的偶數都是兩個素數(只能被1和它本身整除的數)之和。如6=3+3,14=3+11等等。公元1742年6月7日哥德巴赫寫信給當時的大數學家歐拉,歐拉在6月30日給他的回信中說,他相信這個猜想是正確的,但他不能證明。敘述如此簡單的問題,連歐拉這樣首屈一指的數學家都不能證明,這個猜想便引起了許多數學家的註意。從哥德巴赫提出這個猜想至今,許多數學家都不斷努力想攻克它,但都沒有成功。
我們不需要你去證明哥德巴赫猜想。
如果哥德巴赫猜想是正確的,一個(不小於6的)偶數,都是兩個素數之和。那麽這個偶數能被至少一個素數對表示,如14,即可以表示為14=3+11,也可以表示為14=7+7。不同的偶數對應的素數對的數目是不一樣的,如偶數6,就只能表示為6=3+3。對於每個給定的偶數,我們希望知道有多少素數對的和等於該偶數。

Input

有多組測試數據。每組測試數據占一行,包含唯一的一個正偶數n.(6 <= n <= 2^24,)。 輸出以EOF結束。

Output

對於每個輸入的偶數,輸出一行包含唯一的一個整數:表示有多少個素數對的和是輸入的偶數。

Sample Input

6
14

Sample Output

1
2

Source

2009湘潭邀請賽

題解:

本題n最大可以達到2^24,我們就考慮用一種方法,把所有小於2^24的素數都找出來;

顯然枚舉1到2^24每個數,直接用sqrt(n)的復雜度來檢測是否為素數的方法是不太可行的;

因此使用篩法來求所有小於等於N的素數:

①埃篩(埃拉托斯特尼篩法)

  樸素的思想:素數的倍數必然不為素數。

  實現方法:先假設在1~N的範圍內所有的數為素數,例如使用標記數組isPrime[N],就全部先標記為1;然後isPrime[0]=isPrime[1]=0;

       然後i = 2 to sqrt(N)枚舉每個數,如果isPrime[i],則枚舉j = 2i , 3i , 4i , …… , ki ( ki <= N 且 (k+1)i > N ),全部isPrime[j]=0;

  反證法:假設存在一個數n,它是一個合數,但是isPrime[n]=1,則按照算法,n不存在一個因數滿足小於等於sqrt(n)(要是有,n就被篩釣了);

      因此,n必然有一個因數m,滿足sqrt(n) < m < n,則必然存在另一個數 M 滿足 M * m = n,則M必然小於sqrt(n),這與前面相矛盾,故n必然是素數;

用這樣的篩法,我們就可以寫出本題的AC代碼:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #define MAX 16777220
 5 bool isPrime[MAX];
 6 int n;
 7 void screen()//埃篩求素數
 8 {
 9     memset(isPrime,1,sizeof(isPrime));
10     isPrime[0]=isPrime[1]=0;
11     int sqrt_MAX=(int)ceil(sqrt(MAX));
12     for(int i=2;i<=sqrt_MAX;i++)
13     {
14         if(isPrime[i]) for(int j=i*2;j<=MAX;j+=i) isPrime[j]=0;
15     }
16 }
17 int main()
18 {
19     screen();
20     while(scanf("%d",&n)!=EOF)
21     {
22         int cnt=0;
23         for(int i=1;i<=n/2;i++)
24         {
25             if(isPrime[i] && isPrime[n-i]) cnt++;
26         }
27         printf("%d\n",cnt);
28     }
29 }

②歐拉篩法(線性篩法):

  埃篩存在一個缺陷:重復劃去某些合數,例如6,既是2的倍數,又是3的倍數,那麽它就會被重復劃去;

  因此采用一種更加優化的方法篩出素數;

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #define MAX 16777220
 5 int n;
 6 bool isPrime[MAX];
 7 int PrimeNum[MAX/5],cnt=0;
 8 void screen()//歐拉篩法求素數
 9 {
10     memset(isPrime,1,sizeof(isPrime));
11     isPrime[0]=isPrime[1]=0;
12     for(int i=2;i<=MAX;i++)
13     {
14         if(isPrime[i]) PrimeNum[cnt++]=i;
15         for(int j=0;j<cnt;j++)
16         {
17             if(i*PrimeNum[j]>MAX) break;
18             isPrime[(i*PrimeNum[j])]=0;
19             if(i%PrimeNum[j]==0) break;
20                 //比i*PrimeNum[j]更大的數,會被PrimeNum[0]~PrimeNum[j]的素數篩掉
21         }
22     }
23 }
24 int main()
25 {
26     screen();
27     while(scanf("%d",&n)!=EOF)
28     {
29         int cnt=0;
30         for(int i=1;i<=n/2;i++)
31         {
32             if(isPrime[i] && isPrime[n-i]) cnt++;
33         }
34         printf("%d\n",cnt);
35     }
36 }

NEFU 2 - 猜想 - [篩法求素數]