素数:只能被1和本身整除,注意1既不是素数也不是合数。
因此,我们能够想到的最直接、最暴力的方法就是,假设判断i是否为素数,代码如下
for(int j = 2; j < i; j++)
{
// i存在除了1和本身以外的因子,不是素数
if(i % j == 0) break;
}
但是,一般的题目中要求我们判断是否是素数的个数太多,而且判断素数只是程序中很小的一部分,那么就很容易造成双重循环,提交时造成超时。此时的复杂度O(n)
由此,我们想到了,优化的方法,使用开根号的办法。优化后的复杂度O(sqrt(n))。
// 判断n是否为素数
bool isPrime(int n)
{
// 如果n为1或者0或者负数,不是素数,
if (n <= 1) return false;
// sqrt的参数为float型,1.0*将n浮点化,最后再用(int)强制转换
int sqr = (int)sqrt(1.0*n);
// 遍历2-开根号
for (int i = 2; i <= sqr; i++) {
// n有除1和本身以外的因子,不是素数
if (n%i == 0) return false;
}
return true;
}
但是,我们仍然可以采用更加优化的方法埃氏筛法。主要代码如下:
const int maxn = 100001;
int prime[maxn], pNum; // prime存储素数的数组,pNum计数素数的个数
bool p[maxn] = { 0 }; // 表示i为素数即false,不是素数即true
void Find_Prime(int n)
{
// 注意此处不能用i<=maxn
for (int i = 2; i < maxn; i++) {
if (p[i] == false) {
prime[pNum++] = i;
for (int j = i + i; j < maxn; j += i) {
p[j] = true;
}
}
}
}
有了以上的基础后,我们再来实现pat乙级中的1013数素数问题。
首先,我们利用埃氏筛法将前n个素数保存至prime数组中。然后按照要求输出即可。
我在提交该题时,有一个测试用例一直无法通过,后来才发现是设置的maxn值太小了,n是指第n个素数,并不是n之前的素数,也就是第n个素数完全有可能比n大的多。AC的代码如下
#include <stdio.h>
#include <stdlib.h>
const int maxn = 1000001;
int prime[maxn], pNum; //prime存储素数,pNum计数素数个数
bool p[maxn] = { 0 }; //p[i]==false,表示是素数
// 素数表
void Find_Prime(int n) {
for (int i = 2; i < maxn; i++) {
if (p[i] == false) {
prime[pNum++] = i; //存储素数
if (pNum >= n) break;
for (int j = i + i; j < maxn; j += i) {
p[j] = true;
}
}
}
}
int main()
{
int m, n;
if (scanf("%d %d", &m, &n)) {
Find_Prime(n);
int count = 0; //记录输出素数的个数
for (int i = m; i <= n; i++) {
printf("%d", prime[i - 1]);
count++;
if (count % 10 != 0 && i < n) printf(" ");
else printf("\n");
}
}
return 0;
}