1. 程式人生 > 其它 >素數判斷和大合數分解_C004素數的判定作品展示

素數判斷和大合數分解_C004素數的判定作品展示

技術標籤:素數判斷和大合數分解

C004素數的判定作品展示

1號作品 作者:常晨龍

解題思路:若一個數i不能被2~sqrt(i)間任意一個整數整除,那麼i就為質數。

程式程式碼:

#include#includeint main(){  int f,i,j,t=0;  for(i=2;;i++) //從2開始依次判斷每個整數是不是質數  {    f=sqrt((float)i);//VC++2010重構多個sqrt,選其一    for(j=2;j<=f;j++)      if(i%j==0)        break;    if(j>=f+1)      t++;  //用於計數,當前為第t個素數    if(t==2019)      break;  }  printf("%d",i);  return(0);}

執行結果:17569

2號作品作者:網安興國

解題思路:本題目主要運用了常見的三種方法來做,其實後面兩種篩選法在這道題上優勢不大,僅供大家交流學習。

/*由素數定理可知,不超過x的素數的個數為x/lnx,由此大致估計,第2019個素數的大小10000-100000之間*/

#include

#include

#include

using namespace std;

const int maxn = 100000;

bool IsPrime_2[maxn];

bool IsPrime_3[maxn];

int prime[2050];

bool IsPrime(int n) //方法一:判斷n是否為素數,樸素做法,後面要呼叫

{

inti,k;

k= sqrt(n);

for(i=2;i<=k;i++)

if(n % i == 0)

break;

if(i> k)

return true;

returnfalse;

}

/*方法二:埃拉斯托特尼篩選法求素數,其原理是大於等於2的數的n(n>=2)倍一定是合數,因為每一個素數都只能被1和本身除盡,

所以,能夠被這些數篩掉的一定是合數,這樣,留下來的一定是素數。所以我們只需要從2開始,將所有2的倍數(>=2倍)標記為合數,

然後從3開始,將3的倍數(>=2倍)標記為合數,以此類推……當然,對於每個數來說篩選的邊界是maxn(這道題是100000以內)

*/

//方法二:埃拉斯托特尼篩選法求素數,時間複雜度為O(n*ln(n))

//注:本方法的時間複雜度的證明需要用到尤拉推出的關於p級數(p=1時)的求和公式,在此就不做詳盡證明,啊,偉大的尤拉,膜拜。

int Erato() //返回第2019個素數

{

//有一個細節是,每一輪篩選開始的時候,如果該數沒有被標記為false,那麼它一定是素數,因為比它小的數都沒能幹掉它! 所以,能留下來的都是王者!

inti,j,cnt = 0;

memset(IsPrime_2,true,sizeof(IsPrime_2));//將該陣列初始化,全部標記為素數

for(i=2;i<=maxn;i++)

{

if(IsPrime_2[i]) //如果是素數,則計數

cnt++;

if(cnt == 2019) //當得到第2019的數時

returni;

for(j=i*2;j<=maxn;j+=i)

IsPrime_2[j]= false;

}

}

/*方法三:本方法還是篩選,主要利用一個素數基本定理的變形:任何一個合數都可以表示為一個素數和一個合數的乘積,所以,

我們只需要用素數和某一個數的乘積作為篩選標準,且保證每一個合數都是被其最小的素數因子篩掉的,這一點很重要,後面會提到。利用這一點,當篩選的時候,碰到某數n可以整除已經篩出的某素數的時候,本輪篩選便可以停止,因為下一個素數乘n一定可以表示為更小的素數和更大的合數之積,所以就不必重複篩選。這個是重要的減少複雜度的依據,也是本方法的關鍵!每次篩選的時候,都利用已經篩出的素數作為新一輪篩選的基礎。這個篩選要多出一個prime陣列,實際上是以空間換時間。

*/

int Euler() //方法三:尤拉篩選法求素數,時間複雜度為O(n)

{

inti,j,cnt = 0;

memset(IsPrime_3,true,sizeof(IsPrime_3));//將所有數初始化為素數

for(i=2;i<=maxn;i++)

{

if(IsPrime_3[i])

prime[cnt++]= i;

if(cnt == 2019)

returnprime[cnt-1];

for(j=0;j

{

IsPrime_3[i*prime[j]]= false;

if(i% prime[j] == 0) //如果可以整除,則跳出去,前面提到過,這是關鍵之處

break;

}

}

}

int main()

{

inti,cnt = 0;

ios::sync_with_stdio(false);

//方法一樸素做法,時間複雜度為O(n*根號n),具體證明應該會涉及到p級數及留數定理,此處略(其實是本菜雞太弱。。本學期剛開始學複變函式,還沒學到留數定理。。只知道皮毛,不敢妄言。)

for(i=2;i<=maxn;i++)

{

if(IsPrime(i)) //一個一個判斷,如果是素數,則讓計數器cnt加1

cnt++;

if(cnt == 2019)

{

cout<(樸素做法)第2019個素數為:"<

break;

}

}

//方法二:埃拉斯托特尼篩選法

cout<(埃拉斯托特尼篩選法)第2019個素數為:"<

//方法三:尤拉篩選法

cout<(尤拉篩選法)第2019個素數為:"<

return0;

}

執行結果:17569

91396e04ff9a736393e87fafbcc0630b.png

編後記

大部分程式設計教材都有素數判定例程,所以本期題目算是一個常規題,難度不大。本次共收到7份作品,除開己經展示的作品以外,還有李飛陽、宋雲肥、荃渡、pzd、張恆等也提供了作品。本次題目只是找出指定的一個素數,並沒必要把所有的數都儲存下來,所以,從程式的空間複雜性來說,樸素篩選法更為簡單。由於篇幅限制,未能一一展示其他作品。在此,感謝所有作者及支援本公眾號的同學。

1915f11bff58b986298f0d65d3369a32.png

題目連結:C004素數的判定

a7a38cf62c65990aabbd3b1d0b5ffb97.png