ACM-判素数

来源:互联网 发布:计算机最小的数据单位 编辑:程序博客网 时间:2024/04/29 01:39

这篇文章我们将讨论如何求素数,所谓素数即只能被1和本身整除的数,那么毫无疑问,对于一个数n是不是素数,我们可以直接进行判断,即从2~n-1一一进行枚举,如果n都不能被整除,那么说明n就是素数。如果直接暴力判断,需要注意两点:

1、n不能太大

2、只需判断n的根号次

下面是判定素数的源代码:

#include <cmath>int IsPrime(int n){    for(int i=2; i<=sqrt(1.0*n); ++i)        if(n%i == 0)            return 0;    return 1;}

很明显,这样直接枚举判断的时间复杂度很高,下面就讲一种新的方法:筛法,如果用筛法构造素数,可以在很短的时间内算出10^6以内的所有素数,其复杂度为nlog(n)。筛法的原理简单来说就是删除倍数,即对于不超过n的每一个非负整数p,删除2p,3p,4p.,.....,这样处理完每一个p之后,剩下的没有被删除的就是素数,其实这也是素数定义的体现,即能被除了1和自身外的任何数整除的数都不是素数。下面是筛法的源代码:

#include <cmath>#include <cstring>const int MAXN = 1e6;int vis[MAXN+1];int prime[MAXN+1];void IsPrime(int n){    int i, j;    int m = sqrt(n+0.5);    memset(vis, 0, sizeof(vis));    memset(prime, 0, sizeof(prime));    for(i=2; i<=m; ++i) if(!vis[i])    {prime[i] = 1;  // 如果i为素数for(j=i*i; j<=n; j+=i)           vis[j] = 1;    }    for(; i<=n; ++i)    if(!vis[i]) prime[i] = 1;}

一般来说上面的算法已经足够快了,但不是最快,因为在存在重复筛数,比如对于2和4来说,都将8、12、16、......、筛除了。要保证不会重复筛除每一个数,即让算法保持线性,可以从奇偶性方面入手,下面是参考代码:

#include <cmath>#include <cstring>const int MAXN = 1e6;int prime[MAXN+1];void IsPrime(int n){    int i, j, k;    int half = n/2;    int sn = sqrt(n+0.5);    memset(prime, 0, sizeof(prime));    for (i = 0; i < half; i++)        prime[i] = 1;                      // 初始化全部奇数为素数。prime[0]对应3,即p[i]对应2*i+3    for (i = 0; i < sn; i++) if(prime[i])  // 如果 2*i+3 是素数    {        for(k=i+i+3,j=k*i+k+i; j<half; j+=k)        // 筛法起点是 p[i]所对应素数的平方 k^2        // k^2在 p 中的位置是 k*i+k+i        // 下标 i         k*i+k+i        // 对应数值 k=i+i+3   k^2        prime[j] = 0;    }    //prime[i]=1代表 2*i+3 是素数    //比如3是素数,按3*3,3*5,3*7...的次序筛选,因为只保存奇数,所以不用删3*4,3*6....}

这里给一道有关素数的题目,HDOJ:1262,时空转移(点击打开链接),题目如下:

寻找素数对

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8227    Accepted Submission(s): 4110


Problem Description
哥德巴赫猜想大家都知道一点吧.我们现在不是想证明这个结论,而是想在程序语言内部能够表示的数集中,任意取出一个偶数,来寻找两个素数,使得其和等于该偶数.
做好了这件实事,就能说明这个猜想是成立的.
由于可以有不同的素数对来表示同一个偶数,所以专门要求所寻找的素数对是两个值最相近的.
 

Input
输入中是一些偶整数M(5<M<=10000).
 

Output
对于每个偶数,输出两个彼此最接近的素数,其和等于该偶数.
 

Sample Input
20 30 40
 

Sample Output
7 1313 1717 23
 

题意:
中文的,就不说了,注意答案求得是值最接近的两个素数。
分析:
数据的范围是10000,那么我们就可以先使用筛法判出10000以内的所有素数,然后从m/2开始枚举,保证两个素数的值最接近。
源代码:
#include <cstdio>#include <cmath>#include <cstring>const int MAXN = 1e6;int vis[MAXN+1];int prime[MAXN+1];void IsPrime(int n){    int i, j;    int m = sqrt(n+0.5);    memset(vis, 0, sizeof(vis));    memset(prime, 0, sizeof(prime));    for(i=2; i<=m; ++i) if(!vis[i])    {        prime[i] = 1;        for(j=i*i; j<=n; j+=i)           vis[j] = 1;    }    for(; i<=n; ++i)    if(!vis[i]) prime[i] = 1;}int main(){    int m;    IsPrime(10000);    while(~scanf("%d", &m))    {        int tmp = m/2;        while(tmp >= 2)        {            if(prime[tmp] && prime[m-tmp])            {                printf("%d %d\n", tmp, m-tmp);                break;            }            --tmp;        }    }    return 0;}

其他有关素数的题目还有,HDOJ:1431,2098。
接下来我们将讨论反素数,传送门(点击打开链接)。

0 0
原创粉丝点击