您的位置:首页 > 其它

数论--素数筛选法与整数的素因子分解

2014-11-15 13:17 253 查看


筛法求素数:
素数总是一个比较常涉及到的内容,掌握求素数的方法是一项基本功。
基本原则就是题目如果只需要判断少量数字是否为素数,直接枚举因子2。。N^(0.5),看看能否整除N。
如果需要判断的次数较多,则先用下面介绍的办法预处理。
筛选法的思路是:

要求10000以内的素数,把1-10000都列出来,1不是素数,划掉;2是素数,所有2的倍数都不是素数,划掉;取出下一个幸存的数,划掉它的所有倍数;直到所有素数找完为止。

这种做法的空间复杂度是O(n),时间复杂度O(n/logn)。

const int Max = 1000005;
 bool prime[Max]={0};//0表示素数,1为非素数
 
 //筛选n以内的素数
 void getPrime(int n)
 {   <pre name="code" class="cpp"> prime[0]=0;       
 prime[1]=0;
int i,j; int t; for(i = 2; i <= n; i++) { if(!prime[i]) { for(j = 2; (t=j*i) <= n; j++) prime[t] = 1; } } }



这种方法比较好理解,初始时,假设全部都是素数,当找到一个素数时,显然这个素数乘上另外一个数之后都是合数(注意上面的
i*i , 比 i*2要快点 ),把这些合数都筛掉,即算法名字的由来。
但仔细分析能发现,这种方法会造成重复筛除合数,影响效率。比如10,在i=2的时候,k=2*15筛了一次;在i=5,k=5*6的时候又筛了一次。所以,也就有了快速线性筛法。

快速线性筛法

快速线性筛法没有冗余,不会重复筛除一个数,所以“几乎”是线性的,虽然从代码上分析,时间复杂度并不是O(n)。先上代码
#include<iostream>  
using namespace std;      
const long N = 200000;     
long prime
 = {0},num_prime = 0;      
int isNotPrime
 = {1, 1};     
int main()      
{       
for(long i = 2 ; i < N ; i ++)         
 {              
 if(! isNotPrime[i])                 
 prime[num_prime ++]=i;    
 //关键处1          
 for(long j = 0 ; j < num_prime && i * prime[j] <  N ; j ++)  
 {                 
 isNotPrime[i * prime[j]] = 1;    
if( !(i % prime[j] ) )  //关键处2                    
  break;             
  }          
  }          
  return 0;     
}

首先,先明确一个条件,任何合数都能表示成一系列素数的积。
不管 i是否是素数,都会执行到“关键处1”,
①如果 i都是是素数的话,那简单,一个大的素数
i乘以不大于 i的素数,这样筛除的数跟之前的是不会重复的。筛出的数都是 N=p1*p2的形式,
p1,p2之间不相等
②如果 i是合数,此时
i可以表示成递增素数相乘 i=p1*p2*...*pn, pi都是素数(2<=i<=n), pi<=pj
( i<=j )
p1是最小的系数。
根据“关键处2”的定义,当p1==prime[j]的时候,筛除就终止了,也就是说,只能筛出不大于p1的质数*i。
我们可以直观地举个例子。i=2*3*5
此时能筛除 2*i ,不能筛除 3*i
如果能筛除3*i的话,当 i'等于
i'=3*3*5时,筛除2*i'就和前面重复了。
参考练习题:http://acm.nyist.net/JudgeOnline/problemset.php?typeid=10
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: