2022/10/07拓展上机题解:哥德巴赫猜想

哥德巴赫猜想

在这里插入图片描述

方法一:试除法

注意:

  • i ≤ x i i≤\frac{x}{i} iix是最好的写法。
  • 如果是写成 s q r t ( x ) sqrt(x) sqrt(x),每次判断 i i i是否小于 s q r t ( x ) sqrt(x) sqrt(x)都要调用 s q r t sqrt sqrt这个函数,造成时间的浪费。
  • 也有写成 i × i ≤ x i\times i≤x i×ix的,这种写法也不好,如果 i × i i\times i i×i的结果超数据范围了,那么就会变成负数。
#include<stdio.h>
#include <stdbool.h>
#include<math.h>
#define N 10000
bool vis[4 * N];//false表示是素数,否则不是素数
int prime[N];//存储素数
int cnt = 0;//下标,同时可以计算素数的个数
int main() {
	int x;
	while (scanf("%d", &x)) {
		if (x == 0) break;
		int cp = 0;//统计素数对
		for (int i = 2; i <= x / 2; i++) {
			//判断i和x-i是否都是素数
			int sign = 0;
			for (int j = 2; j <= i / j; j++) {
				if (i % j == 0) {
					sign = 1;
					break;
				}
			}
			if (sign == 1) continue;
			for (int j = 2; j <= (x - i) / j; j++) {
				if ((x - i) % j == 0) {
					sign = 1;
					break;
				}
			}
			if (sign == 0) cp++;
		}
		printf("%d\n", cp);
	}
	return 0;
}

在这里插入图片描述

方法二:埃式筛

思想:质数的倍数一定不是质数,一个合数(非质数)一定能被质数整除。

补充:

  • 质数定理: 1 − n 1-n 1n中有 n l n n \frac{n}{ln n} lnnn个质数
  • 时间复杂度 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)
#include<stdio.h>
#include <stdbool.h>
#include<math.h>
#define N 10000
bool vis[4 * N];//false表示是素数,否则不是素数
int prime[N];//存储素数
int cnt = 0;//下标,同时可以计算素数的个数
int main() {
	int n = 2 << 14;
	for (int i = 2; i <= n; i++) {//判断2-n中的素数
		if (!vis[i]) prime[cnt++] = i;//存储素数
		for (int j = i + i; j <= n; j += i) {
			vis[j] = true;//所有素数的倍数都不是素数 
		}
	}
	int x;
	while (scanf("%d", &x)) {
		int cp = 0;
		if (x == 0) break;
		for (int i = 0; prime[i] <= x / 2; i++)
			if (!vis[x - prime[i]]) cp++;
		printf("%d\n", cp);
	}
	return 0;
}

在这里插入图片描述

方法三:线性筛

n ≈ 1 0 6 n≈10^{6} n106,线性筛和埃氏筛的时间效率差不多,若 n ≈ 1 0 7 n≈10^{7} n107,线性筛会比埃氏筛快了大概一倍。

线性筛这个算法的核心在于筛质数的时候规定一个数只能被它的最小质因数筛掉

#include<stdio.h>
#include <stdbool.h>
#include<math.h>
#define N 10000
bool vis[4 * N];//false表示是素数,否则不是素数
int prime[N];
int cnt = 0;
int main() {
	int n = pow(2, 15);//2 << 14
	for (int i = 2; i <= n; i++) {//先求出所有的素数
		if (!vis[i]) prime[cnt++] = i;//是素数
		for (int j = 0; prime[j] <= n / i; j++) {//剔除掉素数的倍数,也就是非素数
			vis[prime[j] * i] = true;
			if (i % prime[j] == 0) break;
			//这一步是干什么的呢,如果i % prime[j] == 0,prime[j]<i(一定)
			//prime[j]只能是i的最小质因数,也是i*prime[j]的最小质数
			//prime里面的质数是由小到大存储的,如果只有当前的prime[j]能整除i,那么先前的prime都不能,所以先前的prime都不是i的因数,而后面的prime[j]也不可能作为i的最小质因数因为后面的prime比当前的prime[j]大
			//可以直接break了
			//当i % prime[j] != 0时,也就是说prime[j]比i的最小质因数小,且prime[j]是prime[j]*i的因数,所以prime[j]就是prime[j]*i的最小质因数

		}
	}
	int x;
	while (scanf("%d", &x)) {
		if (x == 0) break;
		int cnt = 0;
		for (int i = 0; prime[i] <= x / 2; i++)
			if (!vis[x - prime[i]]) cnt++;
		printf("%d\n", cnt);
	}
	return 0;
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值