一、我们首先来看如何求解质数
定义:除了1和自身之外,无法被其它整数整除的数称之为质数,1不是质数。
解法:
使用回圈来求解,将一个指定的数除以所有小于它的数,若可以整除就不是质数:
//检验质数
bool checkZS(int a)
{
for (int i = 2;i < a;i++)
{
if (0 == a%i)
{
return false;
}
}
return true;
}
//主函数调用
int main()
{int n = 99999;
clock_t start,end;//用于计时
start = clock() ;
for(int i = 1;i <= n;i++)
{
if (checkZS(i))
{
cout<<i<<" ";
}
}
end = clock();
cout<<"\n总共花费了"<<(long double)(end - start)/CLK_TCK<<"秒"<<endl;
}
如何减少回圈的检查次数?如何求出小于N的所有质数?
首先假设要检查的数是N好了,则事实上只要检查至N的开根号就可以了,道理很简单,假设AB = N,如果A大于N的开根号,则事实上在小于A之前的检查就可以先检查到这个数可以整除N。 不过在程式中使用开根号会精确度的问题, 所以可以使用 ii <= N进行检查, 且执行更快 。
再来假设有一个筛子存放1~N,例如:
2 3 4 5 6 7 8 9 10 11 12 …N
先将2的倍数筛去:
2 3 5 7 9 11 13…N
再将3的倍数筛去:
2 3 5 7 11 13 17 19…N
再来将5的倍数筛去,再来将7的质数筛去,再来将11的倍数筛去…,如此进行到最后留下的数就都是质数,这就是Eratosthenes筛选方法(Eratosthenes Sieve Method)
检查的次数还可以再减少,事实上,只要检查6n+1与6n+5就可以了,也就是直接跳过2与3的倍
数,使得程式中的if的检查动作可以减少。
下面我们上代码:
/*
**Eratosthenes求质数方法。
**2019/2/13
**李树人
*/
#include <iostream>
#include <time.h>
using namespace std;
#define n 99999
int main()
{
int a[n+1];//建立一个数组,使a[i] == i,这样通过筛选,将非质数所在位置置0
for (int i = 0;i <= n;i++)
{
a[i] = i;
}
clock_t start,end;//用于计时
start = clock() ;
//每次进行筛选的数,进行优化,实际上只要筛选到 N开放就行
for (int i = 2;i*i <= n;)
{
//从i处开始筛选(比i小的肯定不能被i整除)
for (int j = i;j <= n;j++)
{
//通过while循环.跳过中间置0区域
while(0 == a[j] && j <= n)
{
j++;
}
//假如a[j]能被i整除而且不相等(也就是说不是本身),就把这个位置数值置为0
if (0 == a[j]%i && i != a[j])
{
a[j] = 0;
}
}
//i的步进值优化,即跳过2或3的倍数,每次递增数加大
if((i-1)%6 == 0)
i += 4;
else if((i-5)%6 == 0)
{
i += 2;
}
else
{
i++;
}
}
end = clock();
for(int i = 2;i <= n;i++)
{
if (a[i] != 0)
{
cout<<a[i]<<" ";
}
}
cout<<"\n总共花费了"<<(long double)(end - start)/CLK_TCK<<"秒"<<endl;
return 1;
}
现在回到题目要求:
#include <stdio.h>
#include <math.h>
// Eratosthenes筛选法
void sieveofe(int p[], int n)
{
int i, j;
p[0] = 0;
p[1] = 0;
p[2] = 1;
// 初始化
for(i=3; i<=n; i++) {
p[i++] = 1;
p[i] = 0;
}
int max = sqrt(n);
for(i=3; i<=max; i++){
if(p[i]) {
for(j=i+i; j < n; j+=i) //进行筛选
p[j]=0;
}
}
}
#define MAX 10000
int main(void)
{
int p[MAX+1];
int sum, count, i;
sieveofe(p, MAX);
for(;;) {
scanf("%d", &sum);
if(sum == 0)
break;
count = 0;
for(i=2; i<=sum / 2; i++) {
if(p[i] && p[sum-i])
if(i != sum-i)
count++;
}
printf("%d\n", count);
}
return 0;
}