转~素数求法

  素数判断  2013-09-23 08:43:22

分类: C/C++

素数:只有两个正因数(1和自己)的自然数。素数,作为数论中最基础的理论之一,又是许多著名定理的根源。

几个可以无视的性质:
1. 1不是素数
2. 除了2以为所有偶数都是合数。
提高素数,第一反应都会是如果判断素数,找到我们想要的素数。这里列举几种最常用的判断素数的方法。

1. 朴素判别素数
  简述:即判断一个数N是不是素数,只需要判断从2到N^0.5的数是否能整除N,如果能则不是素数,否则就是素数。
  代码:(无视之...)
  评价:从定义出发,简单易懂,适合初初初学者,但要理解上限为啥是N^0.5。

2. 朴素筛法
    简述:筛法的原理这里就不赘述了,思想就是去掉当前的素数的倍数(因为他们一定是合数)。
    代码:
const int maxn = 10000000;
bool IsNotPrime[maxn]; // 判断是否为素数.

void PrimeNormal(void)
{ // 朴素的筛法. 10000000内0.7s出解.
     int i, j;
     memset(IsNotPrime, 0, sizeof(IsNotPrime)); // 初始赋值所有数都是素数.
     IsNotPrime[1] = 1; IsNotPrime[0] = 1; // 0和1不是素数.
     for (i = 2; i < maxn; i++)
     {
         if (!IsNotPrime[i])
         { // 注意:这里只用素数来筛,因为合数筛时肯定被素数筛过了,所以没必要.
            if (1LL * i * i > 1LL * maxn) continue;
            for(j = i * i; j < maxn; j += i) IsNotPrime[j] = 1;
          }
     }
}

     评价:相对朴素的判断素数,速度上有了质的飞跃,但是仍有些素数的性质没有用上,导致速度不够理想。
     优化:我们可以在朴素筛法上做些显而易见的优化:用到前面提到的可以无视的性质,我们可以把除了2以外的偶数提前判断,这样只要循环奇数即可。


3. 线性筛法
    简述:朴素筛法虽然是筛素数的倍数,但是所有倍数都要筛过去,这是完全没必要的。
    我们可以利用,每个合数必有一个最小质因数,每个合数仅被它的最小质因数筛去正好一次这个性质来优化筛法.
    代码:
const int maxn = 10000000;
bool IsNotPrime[maxn]; // 判断是否为素数.
int PrimeList[maxn]; // 素数列表.
int PrimeNum;

void Prime_Linear(void)
{ // 速度比朴素筛法快2倍以上,该筛法进行稍微修改即可用于求欧拉函数Phi[].
     int i, j;
     memset(IsNotPrime, 0, sizeof(IsNotPrime)); // 初始赋值所有数都是素数.
     IsNotPrime[1] = 1; IsNotPrime[0] = 1; // 0和1不是素数.
     for (i = 4; i < maxn; i += 2) IsNotPrime[i] = 1; // 除2以外的所有偶数都不是素数.
     PrimeNum = 0;
     for (i = 3; i < maxn; i += 2)
     {
         if (!IsNotPrime[i])
          { // 如果是素数则加入素数列表.
             PrimeList[PrimeNum++] = i;
         }
            // 注意:这里与朴素筛法不同,即使合数也要进行筛.
           // 因为这里素数只筛它的素数倍,那么有些合数就可能没被筛掉.
           // 而这些合数就需要合数来晒,而且只要筛到它的最小质因子倍即可(想想为什么?).
       for (j = 0; j < PrimeNum && i * PrimeList[j] < maxn; j++)
       {
              IsNotPrime[i * PrimeList[j]] = 1;
             if (i % PrimeList[j] == 0)
              { // 说明PrimeList[j]是i的最小质因子,即i * PrimeList[j]的最小质因子,则跳出.
                  break;
              }
        }
     }
}
    评价:该筛法利用了每个合数必有一个最小质因数,素数只晒素数倍,合数筛到最小质因子倍,复杂度是线性的.

4. 区间筛素数
    简述:有的时候,我们需要知道某个特定区间的素数(区间大小较小,但数可能很大)。
    那么数组就开不下,这时候我们仍然可以使用筛法,只是所有的下标都进行了偏移。
    大家理解下面这段代码可以先用普通筛法写,然后数组下标集体移动即可。

const int maxn = 100000;

int PrimeList[maxn];
int PrimeNum;
bool IsNotPrime[maxn]; // IsNotPrime[i] = 1表示i + L这个数是素数.

void SegmentPrime(int L, int U)
{ // 求区间[L, U]中的素数.
     int i, j;
     int SU = sqrt(1.0 * U);
     int d = U - L + 1;
     for (i = 0; i < d; i++) IsNotPrime[i] = 0; // 一开始全是素数.
     for (i = (L % 2 != 0); i < d; i += 2) IsNotPrime[i] = 1; // 把偶数的直接去掉.
     for (i = 3; i <= SU; i += 2)
     {
           if (i > L && IsNotPrime[i - L]) continue; // IsNotPrime[i - L] == 1说明i不是素数.
           j = (L / i) * i; // j为i的倍数,且最接近L的数.
           if (j < L) j += i;
           if (j == i) j += i; // i为素数,j = i说明j也是素数,所以直接 + i.
          j = j - L;
          for (; j < d; j += i) IsNotPrime[j] = 1; // 说明j不是素数(IsNotPrime[j - L] = 1).
     }
     if (L <= 1) IsNotPrime[1 - L] = 1;
     if (L <= 2) IsNotPrime[2 - L] = 0;
     PrimeNum = 0;
     for (i = 0; i < d; i++) if (!IsNotPrime[i]) PrimeList[PrimeNum++] = i + L;
}

5. Miller_Rabin
简述:很数论的一种方法,需要费马小定理,还要a ^ b的快速幂,还要注意Carmicheal number.
有兴趣可以专门找相关文章看,没兴趣的直接用就哦啦~~
int Modular_Exponent(int a, int b, int MOD)
{ // a ^ b mod MOD.
     int temp(1);
     int aa(a);
     while (b)
     {
          if (b & 1) temp = 1LL * temp * aa % MOD;
          aa = 1LL * aa * aa % MOD;
           b >>= 1;
     }
     return temp;
}

// Carmicheal number: 561,41041,825265,321197185
bool Miller_Rabin(int n, int time = 20)
{ // 如果是素数,则返回1,否则返回0.
   if (n == 1 || (n != 2 && !(n % 2)) || (n != 3 && !(n % 3))
   || (n != 5 && !(n % 5)) || (n != 7 && !(n % 7)))
    return 0;
   while (time--)
     {
           if (Modular_Exponent(((rand() & 0x7fff << 16) +
          rand() & 0x7fff + rand() & 0x7fff) % (n-1) + 1, n - 1, n) != 1)
     return 0;
     }
   return 1;
}

评价:解决了筛法需要连续性判素数的确定,可以在很高概率(多次判断,实际效果很好)判断出素数.


6. 筛法的额外用途:求每个数的最小质因数
简述:原理与筛法相通,只是factor存的是最小质因数,为0当然就是素数啦.
void PrimeFactor(void)
{ // 求每个数最小的质因数.
     int i, j;
     mem(factor, 0);
     factor[1] = 1; factor[0] = 1; // 0和1不是素数.
     PrimeNum = 0;
     for (i = 2; i < maxn; i++)
     {
           if (!factor[i]) PrimeList[PrimeNum++] = i;
          for (j = 0; j < PrimeNum && i * PrimeList[j] < maxn
          && (PrimeList[j] <= factor[i] || factor[i] == 0); j++)
              // 当PrimeList[j] > factor[i] && factor[i] != 0时,那么最小质因数为factor[i].
               // PrimeList数组中的素数是递增的, 当i % PrimeList[j] == 0时,就break,理由同上面的线性筛法.
             factor[i * PrimeList[j]] = PrimeList[j];
             if (i % PrimeList[j] == 0) break;
          }
     }
//    cout << PrimeNum << endl;
}
评价:该方法使用十分巧妙,可以快速地一个数的质因数个数,强烈推荐~~

7. java大数素数判断
简述:此方法极度猥琐...话说导致09年合肥站regional的一堆杯具...
函数:IsProbablePrime(int certainty)
评价:可以用来判断大数是否为素数。

<script type="text/javascript" id="wumiiRelatedItems"> </script>
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值