【PTA刷题整理】PAT 乙级 1007 素数对猜想 + 素数筛选

2020.02.23 , 学习素数筛选算法,同时记住了在初始化时常使用memset() , fill() , 前者的速度较快

1007 素数对猜想 (20分)

让我们定义d​n​​为:d​n​​=p​n+1​​−p​n​​,其中p​i​​是第i个素数。显然有d​1​​=1,且对于n>1有d​n​​是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。
现给定任意正整数N(<10​5​​),请计算不超过N的满足猜想的素数对的个数。
输入格式:
输入在一行给出正整数N。
输出格式:
在一行中输出不超过N的满足猜想的素数对的个数。
输入样例:
20
输出样例:
4


这个题是乙级的一道题目,题意非常的易懂,就是计算给定正整数输入范围内相邻且差为2的素数对的对数,思路当然是先判断得出范围内的哪些数是素数,然后对素数序列进行判断,寻找符合条件的素数对并计数


法一

这些头文件不是全部都用上的,只是做题使用的模板,涵盖了大部分的STL。这种方法使用最普通的求素数的方法,用一个函数判断是否为素数,得出序列后然后进行计算。这里要关注的是这种求素数的方法的时间复杂度是O(n*sqrt(n)),虽说已经可以解出来这道题,但是耗时用了18ms,还是可以进行优化,减少耗时

#include<iostream>                  //输入输出流头文件
#include<stdio.h>                   //标准输入输出
#include<stdlib.h>
#include<math.h>                    //数学函数
#include<string.h>                  //C语言字符数组的字符串
#include<algorithm>                 //C++标准模板库的函数
#include<map>                       //map映射容器
#include<unordered_map>             //无序的map映射容器
#include<vector>                    //变长数组容器
#include<queue>                     //队列
#include<stack>                     //栈
#include<string>                    //C++string类
#include<set>                       //set集合
#define SIZE 500005
using namespace std;                //标准命名空间

                                    //可以加入全局变量或者其他函数

bool isPrime(int n) {
    if (n <= 3) {
        return n > 1;
    }
    //判断一个数能否被小于sqrt(n)的数整除
    int sqrtnum = (int)sqrt(n);
    for (int i = 2; i <= sqrtnum; i++) {
        if(n % i == 0) {
            return false;
        }
    }
    return true;
}

int main(){                         //主函数
#ifdef ONLINE_JUDGE                 //如果有oj系统(在线判定),则忽略文件读入,否则使用文件作为标准输入
#else
    freopen("1.txt", "r", stdin);   //从1.txt输入数据
#endif
	int N;
	cin >> N;
	bool num[N];
	fill(num , num + N , false);
	for(int i = 2 ; i <= N ; i++){
		if(isPrime(i)){
			num[i] = true;
		}
	}
//	for(int k = 0;k <= N ;k++){
//		cout << num[k] << " ";
//	}
//	cout << endl;
	int counter = 0;
//  //打印观察素数标记 
//	for(int i = 2;i <= N ;i++){
//		if(num[i] != false){
//			cout << i << " "; 
//		}
//	}
//	cout << endl;
	for(int i = 2 ; i <= N ; i++){
		int c = 0 , d = 0;
		if(num[i] != 0){
			c = i;
		}
		for(int j = i + 1 ; j <= N ; j++){
			if(num[j] != 0){
				d = j;
				break;
			}
		}
		if(d - c == 2){
			//cout << c << " " << d << endl;
			counter++; 
		}
	}
	cout << counter << endl;
    return 0;                       //返回0,如果不返回0,PAT会报错
}

在这里插入图片描述


法二(素数筛选)

第二种方法使用素数筛选算法,开一个大的bool型数组大小就是n+1就可以了.先把所有的下标初始化为true,基本思想是先假设从2到N的全部数为素数,从2开始扫描,对于数i,可以得知k * i(k = 2 , 3 , 4 ······ k)都不会是素数,这些数至少都有i这个因子 , 每个合数必然有一个质因子,所以可以只用质数来筛选 , 与此同时j的初始条件可以写成 j = i * i , 因为若j 存在某个质因子 , 也会被筛选掉,利用这个规律逐步进行剔除 , 最后总的时间复杂度为 N / 2 + N / 3 + N / 4 + ······ N / N = O(N * log N) , 可以很明显看到耗时减少,比第一种方法筛选的效率更加高

bool isPrime[N + 1];
    //这里的初始化也可以用memset(isPrime , true , sizeof(isPrime)) 
    fill(isPrime , isPrime + N + 1 , true);
    for(int i = 2 ; i < N ; i++){
    	if(isPrime[i]){
    		if(i > N / i){//防止后面i*i溢出 
    			continue;
			}
    		for(int j = i * i ; j <= N ; j += i){
    			isPrime[j] = false;
			}
		}	
	}

完整的题目解法如下

#include<iostream>                  //输入输出流头文件
#include<stdio.h>                   //标准输入输出
#include<stdlib.h>
#include<math.h>                    //数学函数
#include<string.h>                  //C语言字符数组的字符串
#include<algorithm>                 //C++标准模板库的函数
#include<map>                       //map映射容器
#include<unordered_map>             //无序的map映射容器
#include<vector>                    //变长数组容器
#include<queue>                     //队列
#include<stack>                     //栈
#include<string>                    //C++string类
#include<set>                       //set集合
using namespace std;                //标准命名空间

                                    //可以加入全局变量或者其他函数

int main(){                         //主函数
#ifdef ONLINE_JUDGE                 //如果有oj系统(在线判定),则忽略文件读入,否则使用文件作为标准输入
#else
    freopen("1.txt", "r", stdin);   //从1.txt输入数据
#endif
    int N,i,j;
    cin >> N;
    bool isPrime[N + 1];
    //这里的初始化也可以用memset(isPrime , true , sizeof(isPrime)) 
    fill(isPrime , isPrime + N + 1 , true);
    for(int i = 2 ; i < N ; i++){
    	if(isPrime[i]){
    		if(i > N / i){//防止后面i*i溢出 
    			continue;
			}
    		for(int j = i * i ; j <= N ; j += i){
    			isPrime[j] = false;
			}
		}	
	}
	int counter = 0;
	for(int i = 2 ; i <= N ; i++){
		int c = 0 , d = 0;
		if(isPrime[i]){
			c = i;
		}
		for(int j = i + 1 ; j <= N ; j++){
			if(isPrime[j]){
				d = j;
				break;
			}
		}
		if(d - c == 2){
			//cout << c << " " << d << endl;
			counter++; 
		}
	}
	cout << counter << endl;
    return 0;                       
}

在这里插入图片描述

发布了13 篇原创文章 · 获赞 1 · 访问量 268

猜你喜欢

转载自blog.csdn.net/weixin_43849089/article/details/104463329