【hiho_week251】歌德巴赫猜想及质数筛法

  • 原题
  • 我的答案
  • 解析与思考
  • 质数筛法

原题

https://hihocoder.com/contest/hiho251

描述

哥德巴赫猜想认为“每一个大于2的偶数,都能表示成两个质数之和”。
给定一个大于2的偶数N,你能找到两个质数P和Q满足P<=Q并且P+Q=N吗?

输入

一个偶数N(4 <= N <= 1000000)

输出

输出P和Q。如果有多组解,输出P最小的一组。


我的答案

题目感觉很简单,就是循环遍历小于等于N/2的质数P,若是Q也为质数,则(P,Q)满足要求。于是,我觉得主要就是如何判断质数,这个也很简单,就是看2到根号n之间有没有可以整除n的数。

#include 
#include 
// 判断n是否是质数
int if_prime(int n) {
	for (int i = 2; i < sqrt(n); i++) {
		if (n%i==0) {
			return 0;
		}
	}
	return 1;
}

int main(int argc, char** argv) {
	int n;
	scanf("%d", &n);
	for (int i = 2; i <= n/2; i++) {
		if (if_prime(i)) {
			if (if_prime(n-i)) {
				printf("%d %d\n", i, n-i);
				return 0;
			}		
		}
	}
	return 0;
}

解析与思考

解析

由于题目N的范围最大只有1000000,所以我们可以筛出1000000以内的所有质数,并且保存在哈希表里备查。
然后从小到大枚举质数P,检查N-P是不是在哈希表里即可。

思考

按我这样做,最坏的情况下,时间复杂度会超过O(n),如果筛选[1,N]间质数时间复杂度O(n)级那也是极好的。感觉都用不着哈希表,直接用N个元素的数组存0/1表示是否是质数即可

质数筛法

1.Eratosthenes筛法

若一个数是质数,则其倍数是合数。
建立一个布尔类型的数组isPrime,初始化都为true。从2开始枚举,当找到一个isPrime[p]仍然为true时,可以确定p一定是一个质数。接着再将N以内所有p的倍数全部设定为isPrime[p*i]=false。

但是很多合数都被查询不止一次,时间复杂度上O(nlogn)。
PS.对于埃氏筛法时间复杂度的计算,可以阅读 Eratosthenes筛法(埃式筛法)时间复杂度分析

2.Eular质数筛法

改进之后,只利用k的最小质因子去计算一次k。枚举的时候,我们只枚举i的质数倍。
此外,在从小到大依次枚举质数p来计算i的倍数时,我们还需要检查i是否能够被p整除。若i能够被p整除,则停止枚举。

#include 
#include 
#include 
using namespace std;
//Eular质数筛法  [1, n]中质数 

int main(int argc, char** argv) {
	int n, i;
	scanf("%d", &n);
	bool* isprime = (bool*)malloc(sizeof(bool)*n);
	isprime[0] = false;
	int primecount = 0;
	vector primelist;
	for (i = 2; i <= n; i++) {
		isprime[i-1] = true;
	}
	for (i = 2; i <= n; i++) {
		if (isprime[i-1] == true) {
			primecount++;
			primelist.push_back(i);
		}	
		for (int j=0; j < primecount; j++) {
			if (i*primelist[j] > n) {
				break; 
			} 
			else {
				isprime[i*primelist[j]-1] = false;
			}
			if(i % primelist[j] == 0){
				break;
			}
		}
	} 
	printf("%d\n", primecount);
	return 0;
}

你可能感兴趣的:(练习题)