算法竞赛入门经典: 第四章 函数与递归 4.3孪生素数

时间:2022-02-02 14:13:35
/*
孪生素数:
如果n和n+2都是素数,则称他们是孪生素数。输入m,输出两个数均不超过m的最大孪生素数。5<=m<=10000。例如m=20时答案是17,19,m=1000时答案是881,883
*/

/*
关键:
1 用素数筛选法先预处理,默认刚开始全为素数,然后对素数的倍数标记为非素数,			for(int j = i*i ; j <= 10000 ; j += i){iPrimeArr[j] = 1;}
2 通过开根号判断素数时,可以用floor,注意浮点数加上0.5,int iRadical = floor(sqrt(n*1.0) + 0.5);
3 可以用assert()对输入的合法性进行校验,assert(n >= 5 && n <= 10000);void assert(int exp),如果表达式的值为0则退出。
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>
//#include <memory.h>

#define MAXSIZE 10000 + 1
//预处理,进行素数筛选法,求出素数,然后从m开始向后逆推

bool isPrime(int n)
{
	//判断数字是否小于等于0
	assert(n > 0);
	if(1 == n)
	{
		return false;
	}
	//int iRadical = (int)sqrt(n*1.0);//radical根号,根据浮点数运算丢失精度,这里加上0.5
	int iRadical = floor(sqrt(n*1.0) + 0.5);
	bool is_prime = true;
	for(int i = 2 ; i <= iRadical ; i++)
	{
		if( n % i == 0)
		{
			is_prime = false;
			break;
		}
	}
	return is_prime;
}

void findPrime(int m)
{
	//预处理
	//bool bPrimeArr[MAXSIZE] = {true};//初始化默认均为素数
	int iPrimeArr[MAXSIZE];//初始化默认都为素数
	memset(iPrimeArr,0,sizeof(iPrimeArr));
	for(int i = 2 ; i <= 10000 ; i++)
	{
		if(iPrimeArr[i] == 0)//如果是素数,就将其倍数标记为非素数
		{
			for(int j = i*i ; j <= 10000 ; j += i)
			{
				iPrimeArr[j] = 1;
			}
		}
	}
	
	//逆推,求孪生素数
	for(int k = m ; k >= 5; k--)
	{
		if(iPrimeArr[k-2] == 0 && iPrimeArr[k] == 0)
		{
			printf("%d %d\n",k-2,k);
			break;
		}
	}
}

void findPrime2(int n)
{
	assert(n >= 5 && n <= 10000);
	for(int i = n-2 ; i >= 3; i--)
	{
		if(isPrime(i) && isPrime(i+2))
		{
			printf("%d %d\n",i,i+2);
			break;
		}
	}
}

int main(int argc,char* argv[])
{
	int m;
	scanf("%d",&m);
	//findPrime(m);
	findPrime2(m);
	system("pause");
	return 0;
}