题目
给你一个自然数N,求[6,N]之内的所有素数中,两两之和为偶数的那些偶数。
解题思路
哥德巴赫猜想:任何大于2的偶数都可以表示成两个素数的和。
单纯的因为哥德巴赫猜想直接打印那些偶数也是不对的,例如,某些偶数(比如22=11+11)不可以拆分为两个不同素数之和。若直接打印偶数也需要判断那些偶数是哪两个不同素数之和(判断一个这样的偶数至少是线性复杂度),不能包含3和5。因此考虑使用枚举方法(时间复杂度O(n^2)):
-
找出[6,N]之间的所有素数;
-
求这些素数两两之和;
-
对得到的素数之和排序、去重、打印。
源程序
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define N (20000)
#define M (N/2)
static int primes[M]; /*编译器初始化了0*/
static int sums[M*M]; /*任意两素数之和*/
int my_cmp (const void * a, const void * b);
/* 判断一个数是不是素数,是素数则返回它自己;否则返回0 */
int is_prime (int x){
int i,t;
int ans = 0;
if (x<=1 || 0==x%2){
return ans;
}
t = (int)sqrt (x);
for (i=3;i<=t;i+=2){
if (0 == x%i){
return ans;
}
}
return (ans = x);
}
/* 保存区间的素数到全局数组primes */
void primes_in (int low, int high){
int i=0,j=low;
while (j<=high){
if (is_prime (j)){
primes[i++]=j;
}
j++;
}
}/*数组中的非零元素就是区间中的素数 */
/*求区间中素数的和并打印出来 */
void solve (int left, int right){
int i,j,k;
int t; /*记录素数的个数*/
primes_in (left,right);
for (t=0; t<M; t++){
if (!primes[t]){
break;
}
}
for (k=0,i=0; i<t; i++){
for (j=i; j<t; j++){
sums[k++]=primes[i]+primes[j];
}
}
/*排序*/
qsort (sums, k, sizeof (int), my_cmp);
/*去重*/
i=0;
for (j=i+1; j<k; j++){
if (sums[j] > sums[i]){
sums[++i] = sums[j];
}
}
/*打印*/
for (j=0;j<=i;j++){
printf ("%d, %d\n", j+1, sums[j]);
}
}
int my_cmp (const void * a, const void * b){
return (*(int *)a - *(int *)b);
}
/* 程序入口 */
int main (){
solve (6,N);
return 0;
}