算法笔记练习 5.4 素数 问题 C: Goldbach's Conjecture

算法笔记练习 题解合集

题目链接

题目

题目描述

Goldbach’s Conjecture: For any even number n greater than or equal to 4, there exists at least one pair of prime numbers p1 and p2 such that n = p1 + p2.
This conjecture has not been proved nor refused yet. No one is sure whether this conjecture actually holds. However, one can find such a pair of prime numbers, if any, for a given even number. The problem here is to write a program that reports the number of all the pairs of prime numbers satisfying the condition in the conjecture for a given even number.

A sequence of even numbers is given as input. Corresponding to each number, the program should output the number of pairs mentioned above. Notice that we are interested in the number of essentially different pairs and therefore you should not count (p1, p2) and (p2, p1) separately as two different pairs.

输入

An integer is given in each input line. You may assume that each integer is even, and is greater than or equal to 4 and less than 2^15. The end of the input is indicated by a number 0.

输出

Each output line should contain an integer number. No other characters should appear in the output.

样例输入
4
10
16
0
样例输出
1
2
2

思路

首先埃氏筛法打素数表,题目给的偶数范围是 [ 4 , 2 15 ] [4,2^{15}] [4,215],所以打到稍微大于 2 15 2^{15} 215 就好。

实际上打完表之后问题就转变为双指针了,即在给定的递增数组中,寻找两个数(可以是同一个数)的和为sum,问有几种不同方案。直接用双指针法统计结果即可。

我这里为了复习一下二分查找强行优化了一下,先给双指针法找到一个显然的右端点:想象如果table[i] > sum的话,table[i]一定不会出现在可能的方案中,所以这个显然的右端点就是数组中小于sum的最大元素。

代码

#include 

#define MAX 33000	// 稍微比 2^15 大一点就好

// 埃氏筛法打素数表 
int isPrime[MAX];
int table[MAX]; 
int findPrime(void) {
	int i, j, cnt = 0;
	for (i = 2; i < MAX; ++i)
		isPrime[i] = 1;
	for (i = 2; i < MAX; ++i) {
		if (isPrime[i])
			table[cnt++] = i;
		for (j = i; j < MAX; j += i)
			isPrime[j] = 0; 
	}
	return cnt;
} 

// 二分法寻找长度为 n 的严格递增数组 a 中
// 小于 x 的最大元素,并返回其下标
// 根据题意,x 一定不在 a 中 
int binarySearch(int *a, int n, int x) {
	int left = 0;
	int right = n - 1;
	int mid;
	while (left <= right) {
		mid = left + (right - left) / 2;
		if (a[mid] < x) 
			left = mid + 1;
		else
			right = mid - 1; 
	}
	return a[right] < x ? right : left;
}

// 双指针法统计 [left, right] 范围内
// 两数之和等于 sum 的方案数量
int countGoldbach(int *a, int left, int right, int sum) {
	int cnt = 0;
	while (left <= right) {
		if (a[left] + a[right] == sum){
			++cnt;
			++left;
			--right;
		} else if (a[left] + a[right] < sum) 
			++left;
		else
			--right; 
	}
	return cnt;
} 
 
int main() {
	int cnt = findPrime();
	int n;
	while (scanf("%d", &n) != EOF) {
		if (n == 0) continue;
		int right = binarySearch(table, cnt, n);
		printf("%d\n", countGoldbach(table, 0, right, n)); 
	} 
} 	

你可能感兴趣的:(算法笔记)