HDU2098-分拆素數和


分拆素數和

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10263    Accepted Submission(s): 4434


Problem Description
把一個偶數拆成兩個不同素數的和,有幾種拆法呢?
 

 

Input
輸入包含一些正的偶數,其值不會超過10000,個數不會超過500,若遇0,則結束。
 

 

Output
對應每個偶數,輸出其拆成不同素數的個數,每個結果占一行。
 

 

Sample Input
30 26 0
 

 

Sample Output
3 2
 

方法一

// e.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


#include <stdio.h>
#include <math.h>
int main()
{
int n,a[10000],i,T,l,j,count;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
count=l=0;
for(i=2;i<=n-2;i++)
{
T=1;
for(j=2;j<=sqrt(i);j++)
{
if(i%j==0)
{
T=0;
break;
}
}
if(T==1)
{
a[l++]=i;

}
}
for(i=0;i<l;i++)
{

for(j=i+1;j<l;j++)
{
if(a[i]+a[j]==n)
count++;
}

}
printf("%d\n",count);
}
return 0;
}

問題分析(摘引):

求質數的文章: [原創]求質數(C語言描述) 【問題描述】:

試編寫一個程序,找出2->N之間的所有質數。希望用盡可能快的方法實現。

【問題分析】:

這個問題可以有兩種解法:一種是用“篩子法”,另一種是從2->N檢查,找出質數。
先來簡單介紹一下“篩法”,求2~20的質數,它的做法是先把2~20這些數一字排開:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
先取出數組中最小的數,是2,則判斷2是質數,把后面2的倍數全部刪掉。
2 | 3 5 7 9 11 13 15 17 19
接下來的最小數是3,取出,再刪掉3的倍數
2 3 | 5 7 11 13 17 19
一直這樣下去,直到結束。
篩法求質數的問題時,非質數的數據有很多是重復的。例如,如果有一個數3×7×17×23,那么在刪除3的倍數時會刪到它,刪7、17、23時同樣也會刪到它。有一種“線性篩法”,可以安排刪除的次序,使得每一個非質數都只被刪除一次。從而提高效率。因為“篩法”不是我要介紹的重點,所以就不介紹了。
現在我來介紹第二種方法。用這種方法,最先想到的就是讓從2~N逐一檢查。如果是就顯示出來,如果不是,就檢查下一個。這是正確的做法,但效率卻不高。當然,2是質數,那么2的倍數就不是質數,如果令i從2到N,就很冤枉地測試了4、6、8……這些數?所以第一點改建就是只測試2與所有的奇數就足夠了。同理,3是質數,但6、9、12……這些3的倍數卻不是,因此,如果能夠把2與3的倍數跳過去而不測試,任意連續的6個數中,就只會測試2個而已。以6n,6n+1,6n+2,6n+3,6n+4,6n+5為例,6n,6n+2,6n+4是偶數,又6n+3是3的倍數,所以如果2與3的倍數都不理會,只要測試的數就只留下6n+1和6n+5而已了,因而工作量只是前面想法的2/6=1/3,應該用這個方法編程。
還有個問題,就是如果判斷一個數i是否為素數。按素數的定義,也就是只有1與本身可以整除,所以可以用2~i-1去除i,如果都除不盡,i就是素數。觀點對,但卻與上一點一樣的笨拙。當i>2時,有哪一個數可以被i-1除盡的?沒有,為什么?如果i不是質數,那么i=a×b,此地a與b既不是i又不是1;正因為a>1,a至少為2,因此b最多也是i/2而已,去除i的數用不着是2~i-1,而用2~i/2就可以了。不但如此,因為i=a×b,a與b不能大於sqrt(i),為什么呢?如果a>sqrt(i),b>sqrt(i),於是a×b>sqrt(i)*sqrt(i)=i,因此就都不能整除i了。如果i不是質數,它的因子最大就是sqrt(i);換言之,用2~sqrt(i)去檢驗就行了。
但是,用2~sqrt(i)去檢驗也是浪費。就像前面一樣,2除不盡,2的倍數也除不盡;同理,3除不盡,3的倍數也除不盡……最理想的方法就是用質數去除i。
但問題是這些素數從何而來?這比較簡單,可以准備一個數組prime[],用來存放找到的素數,一開始它里面有2、3、5。檢查的時候,就用prime[]中小於sqrt(i)的數去除i即可,如果都除不盡,i就是素數,把它放如prime[]中,因此prime[]中的素數會越來越多,直到滿足個數為止!
不妨用這段說明來編寫這個程序,但是程序設計的時候會有兩個小問題:
1.如果只檢查6n+1和6n+5?不難發現,它們的距離是4、2、4、2……所以,可以先定義一個變量gab=4,然后gab=6-gab;
2.比較是不能用sqrt(i),因為它不精確。舉個例子,i=121,在數學上,sqrt(i)自然是11,但計算機里的結果可能是10.9999999,於是去除的數就是2、3、5、7,而不含11,因此121就變成質數了。解決這個問題的方法很簡單,不要用開方,用平方即可。例如,如果p*p<=i,則就用p去除i。而且它的效率比開方高。

【程序清單】:

 

#include <stdio.h>

int creat_prime(int prime[],int n,int total)
{
register int i;
register int j;
register int gab=2;
register int count;
for(i=7;i<=n;i+=gab)
{
count=1;
gab=6-gab;
for(j=0;prime[j]*prime[j]<=i;j++)
{
if(i%prime[j]==0)
{
count=0;
break;
}
}
if(count)
{
prime[total]=i;
total++;
}
}

return total;
}

int main(void)
{
int prime[30000]={2,3,5};
int total=3; //找到素數的個數
int i;
int n=200000; //要查找的范圍(>=6)

total=creat_prime(prime,n,total);
for(i=0;i<total;i++)
{
printf("%d ",prime[i]);
if(i && !(i%10))
putchar('\n');
}
putchar('\n');
}



 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM