关于这道题目
需要解决的点主要是
- 判断一个数是不是素数
- 如何有效的减枝
判断一个数是不是素数
判断一个数是不是素数有很多种做法,比如试除法
今天呢使用一个更快的办法米勒测试
主要的原理是根据费马小定理
定理描述
当且仅当 P 为素数时:
ap-1 mod P 为 1
1 <= a <= p - 1
那么我们只需要选取若干个a,代入以上公式
求得结果,若均为1,说明 P 在很大概率上是个素数
代码如下
/************************************************************************* > File Name: 1.c > Author:Gin.TaMa > Mail:1137554811@qq.com > Created Time: 2019年01月08日 星期二 11时52分13秒 ************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define test_round 30
int r_m_test(int x){
if(x <= 1)return 0;
//注意对函数的输入范围进行限制,这才是一个良好的函数定义方法
int a , m, ans ;
for(int i = 0;i < test_round;i ++){
a = rand()%(x - 1) + 1;
m = x - 1;
ans = 1;
while(m){
if(m & 1)ans = ans * a % x;
a = a * a % x;
m >>= 1;
}
if(ans != 1)return 0;
}
return 1;
}
int main(){
srand(time(0));
for(int i = 2;i < 100;i ++){
if(r_m_test(i))printf("%d\n",i);
}
return 0;
}
这里有两点需要注意的是
-
ans 需要初始化 为 1
凡是涉及到累乘的变量 初始化 为 1
累加的变量 初始化 为 0
-
对函数的输入范围进行限制,这才是一个健壮的函数定义方式
如何剪枝呢?
-
考虑i = 0时 b 需要为 素数
-
考虑i = 1时 a + b + 1 需要为素数
-
对于 x * x + a * x + b 这个式子的上界会是多少
也就是说到某个最小的可能合数,也就是a,b的最小公因子
结合上诉分析,我们需要一个素数筛的变形形式,来保留每个数字的最小素因子
for(int i = 2; i < max_n;i ++){
if(!prime[i])
for(int j = i ;j < max_n;j += i)
(!prime[j])&&(prime[j] = i);
}
ok 了
接下来就是合起来了
/************************************************************************* > File Name: 1.c > Author:Gin.TaMa > Mail:1137554811@qq.com > Created Time: 2019年01月08日 星期二 11时52分13秒 ************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define test_round 30
#define max_n 10000
int prime[max_n + 5] = {
0};
int gcd(int a,int b){
if(!b)return a;
return gcd(b,a % b);
}
int r_m_test(int x){
if(x <= 1)return 0;// 注意对函数的输入范围进行限制,这才是一个良好的定义函数的方式
int a , m, ans ;
for(int i = 0;i < test_round;i ++){
a = rand()%(x - 1) + 1;
m = x - 1;
ans = 1;// ans = 1;
while(m){
if(m & 1)ans = ans * a % x;
a = a * a % x;
m >>= 1;
}
if(ans != 1)return 0;
}
return 1;
}
int get_leng(int a,int b){
int i = 0;
while(r_m_test(i * i + a * i + b))i ++;
return i;
}
void init(){
for(int i = 2;i < max_n;i ++){
if(!prime[i])
for(int j = i;j < max_n;j += i)
(!prime[j])&&(prime[j] = i);
}
}
int main(){
srand(time(0));
init();
int ans = 0,temp_l = 0,max_l = 0;
for(int a = -999;a < 1000;a ++){
for(int b = 2;b < 1000;b ++){
if(prime[b] != b)continue;
if(prime[a + b + 1]!= a + b + 1)continue;
if(a > 0 && b > 0 && prime[gcd(a,b)] <= max_l)continue;
temp_l = get_leng(a,b);
if(temp_l > max_l){
ans = a * b;
max_l = temp_l;
}
}
}
printf("%d\n",ans);
return 0;
}