问题概述
题目:算法-哥德巴赫猜想-
问题描述(原题是英文,这里是翻译过后的版本):
对于任意n大于或等于4的偶数,至少存在一对质数p1和p2,使n = p1 + p2。这个猜想至今没有被证实,也没有被否定。没人能确定这个猜想是否成立。然而,如果有的话,为一个给定的偶数,人们可以找到这样一对素数。这里的问题是,编写一个程序,对于给定的偶数,报告满足猜想条件的所有质数对的数目。
一个偶数序列作为输入。对应于每个数字,程序应该输出上述对的数量。注意,我们感兴趣的是本质上不同的对的数量,因此你不应该把(p1, p2)和(p2, p1)分别算作两对不同的对。
输入:
每个输入行都有一个整数。你可以假设每个整数都是偶数,大于或等于4小于2^15。输入的末尾用数字0表示。
输出:
每个输出行应该包含一个整数。输出中不应该出现其他字符。
样例输入:
4
10
16
0
样例输出:
1
2
2
1. 问题分析
1.1 算法核心
验证哥德巴赫猜想是经典的数学算法题,也就是数学问题用计算机来解决,因而算法核心就是数学模拟问题;
1.2 算法分析
因为我们要找素数对,所以得先有一个素数表嘛,第一步先写一个标准埃氏筛选法获得素数表,这里素数表可以取的大一点,因为系统输入的这个整数不超过215,所以我们的素数表可以取大一点。
有了素数表以后就可以数学模拟了,要找到一对素数满足素数对和等于某个整数,那肯定是一大一小,或者两个差不多大的素数,根据题目得知(p2,p1)和(p1,p2)这两对素数只算一组不同的素数对;
诶,这个时候我突然想到了算法中常用的小技巧-two pointers,定义两个指针,一个从素数表首开始,一个从素数表尾开始,这样不仅可以优化时间复杂度,也可以避免素数对的重复计数,于是就先根据输入的整数(以下简称为t)找到距离t最近的那个素数,然后让一个指针指向这个位置,然后另一个指针从素数表首开始,
就是把素数表想象成一个线性序列,
第一个指针指向首个元素,
第二个指针指向距离t最大的素数,
然后开始计算素数对的和,
若等于t,那么素数对计数器加一,之后第一个指针向右移动一位第二个指针向左移动一位,
若小于t说明不够大,那第一个指针向右移动一位,
若大于t说明不够小,那第二个指针向左移动一位,
这样不断匹配,直到第一个指针和第二个指针指向同一个元素,或者第一个指针指向的元素大于第二个指针指向的元素,此时终止循环,根据题目要求输出计数器的值即可;
2. 解决方案
#include <iostream>
using namespace std;
#define maxLength 40010
int n, primeTable[maxLength], primeCounts = 0, t;
bool primeSign[maxLength] = { 0 };
void findPrimeTable();
int GoldbachConjecture(int max);
int main()
{
findPrimeTable();
while (scanf("%d", &t) != EOF && t != 0)
{
t = GoldbachConjecture(t);
printf("%d\n", t);
}
return 0;
}
void findPrimeTable()
{
for (int i = 2; i < maxLength; i++)
{
if (primeSign[i] == false)
{
primeTable[primeCounts++] = i;
for (int j = i + i; j < maxLength; j += i)
primeSign[j] = true;
}
}
}
int GoldbachConjecture(int max)
{
int counts = 0, tmp, overlapSign = 1;
int *left, *right;
left = primeTable;
for(int i = 2; i < maxLength; i++)
{
if(primeTable[i] > max)
{
right = &primeTable[i - 1];
break;
}
}
while(*left <= *right && *right >= 2)
{
tmp = *left + *right;
if(tmp == max)
{
counts++;
left++, right--;
}
else if(tmp < max)
left++;
else
right--;
}
return counts;
}
3. 资源分享
旗木白哉のGitHub:
https://github.com/YangMengHeng
C++ / C源代码下载地址:
https://github.com/YangMengHeng/myCode/tree/master/VSCode
Java源代码下载地址:
https://github.com/YangMengHeng/myCode/tree/master/Java
旗木白哉のblog源代码下载地址:
https://github.com/YangMengHeng/myCode/tree/master/%E6%97%97%E6%9C%A8%E7%99%BD%E5%93%89%E3%81%AEblog