返回信息流今天仔细研究了一下素数的问题,得到一些心得写下来:
1.暴力枚举
思路:一个一个去测试到n ,能整除就不是,最后都不能整除的就是素数;
2.暴力枚举
思路:一个一个去测试到sqrt(n) ,能整除就不是,最后都不能整除的就是素数;
总结:稍微有点改进,但是复杂度依然很高
3.算术基本定理
详见:http://baike.baidu.com/link?url=sJLGSh3YXpsTO40Pw8F9ZBQVe-
KjFgY4kaXgO65_vjyNvtFemEYVw0okmK0O0bmZwhcWiCcXgZgXivlMlg9wia
思路:一个合数能唯一表示成素因子之积的形式,所以开个数组存下小于n的素数,然后测试,能整除就不是,最后都不能整除的就是素数;
代码如下:
#include <stdio.h>
#define N 1000005
int p[N];
int main()
{
int n=1000000;
int i,j,k;
int num=0;
p[num++]=2;
for(i=3;i<=n;i++)
{
for(j=0;j<num;j++)
{
if(!(i%2))
break;
if(i%p[j]==0)
break;
}
if(j==num)
p[num++]=i;
}
/*for(k=0;k<num;k++)
{
if(p[k]>n)
break;
printf("%d\n",p[k]);
}*/
printf("素数个数为:%d\n",num);
return 0;
}
总结:每次取余的时候如果遇到后边素数的倍数就要查询好久,在n=100万时已经运行了13s
改进:如果能找到一个直接它的素因子就很好了,这就要用到筛法了
4.筛法
详见:http://baike.baidu.com/view/82625.htm
思路:筛去2,3,。。。,sqrt(n)的倍数,剩下的就是素数
代码:
#include <stdio.h>
#include <math.h>
#define N 100000000
int r[N];
int main()
{
int n=10000000;
int i,j;
int num;
int count=0;
num=sqrt(n);
for(i=2;i<=num;i++)
{
if(r[i])
continue;
for(j=2;i*j<=n;j++)
{
if(r[i*j])
continue;
r[i*j]=1;
}
}
for(i=2;i<=n;i++)
{
if(!r[i])
{
/*printf("%d\n",i);*/
count++;
}
}
printf("1-%d的素数个数为:%d\n",n,count);
return 0;
}
总结:n=1000万只有0.374s,已经非常快了
改进:筛的时候会重复筛选后边的倍数,比如2和3的公倍数6就筛了两遍
5.线性筛
思路:结合筛法和算术基本定理
合数=第一个素因子*合数/合数=素数*素数
保证每个元素只访问一次
更多信息可见:http://blog.csdn.net/nuanxin_520/article/details/41207145
代码:
#include <stdio.h>
#define N 10000000
int p[N];
int is[N];
int main()
{
int n=10000000;
int i,j;
int num=0;
is[0]=is[1]=1;
for(i=2;i<=n;i++)
{
if(!is[i])
p[num++]=i;
for(j=0;j<num&&i*p[j]<=n;j++)
{
is[i*p[j]]=1;
if(!(i%p[j]))
break;
}
}
printf("1-%d的素数个数为:%d\n",n,num);
return 0;
}
比较:n=1亿时筛法用时2.664s,线性筛用时1.326s,不同编译器或者电脑配置可能稍有不同,但是已经能体现优越性了,数据更大的话应该更明显,大于一亿的数组开不了了,未能验证,不过结果应该正确。
注意:数据量小的时候可能筛法更快,应该是因为筛法只能到了加法和乘法,而线性筛还用了取余操作会比较费时
还有更多更好的办法有待学习,不过平时使用已经满足需求了
记:所有程序均在win7,codeblocks上运行
这是一条镜像帖。来源:北邮人论坛 / acm-icpc / #91095同步于 2016/9/17
ACM_ICPC机器人发帖
统计小于等于n的素数个数问题
dxy1
2016/9/17镜像同步0 回复
订阅后,新回复会通过你的通知中心匿名送达。
0 条回复
暂无回复 · 你可以订阅本帖等待新回复。