【算法】验证哥德巴赫猜想

问题来源

Timus Online Judge 网站上有这么一道题目:1356.
Something Easier
。这道题目的输入是一组  2 到 109 之间整数,对于每个输入的整数,要求用最少个数的素数的和来表示。这道题目的时间限制是 1 秒。

问题解答

我们知道著名的哥德巴赫猜想是:

任何一个充分大的偶数都可以表示为两个素数之和

于是我们有以下的 C 语言程序(1356.c):


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

// http://acm.timus.ru/problem.aspx?space=1&num=1356

#include
<stdio.h>

#include
<stdlib.h>

#include
<math.h>

#include
<time.h>

// http://en.wikipedia.org/wiki/Prime_number_theorem

#define
PRIME_MAX 10000

#define
PRIME_COUNT 1229

typedef unsigned long long U8;

typedef char bool;

const bool true =
1;

const bool false =
0;

// http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

bool*
getSieve(
int max)

{

  static bool sieve[(PRIME_MAX
>> 1) + 1];

  int i,
j, imax = 
sqrt(max);

  for (i
= 3; i <= imax; i += 2)

    if (!sieve[i
>> 1])

      for (j
= i * i; j <= max; j += i << 1) sieve[j >> 1] = 
true;

  return sieve;

}

int*
getPrimes(
int max)

{

  static int primes[PRIME_COUNT
+ 1];

  bool *sieve
= getSieve(max);

  int i,
j = 0;

  for (primes[j++]
= 2, i = 3; i <= max; i += 2)

    if (!sieve[i
>> 1]) primes[j++] = i;

  return primes;

}

U8
modMultiply(U8 a, U8 b, U8 m)

{

  return a
* b % m;

}

U8
modPow(U8 a, U8 b, U8 m)

{

  U8
v = 1, p;

  for (p
= a % m; b > 0; b >>= 1, p = modMultiply(p, p, m))

    if (b
& 1) v = modMultiply(v, p, m);

  return v;

}

bool witness(U8
a, U8 n)

{

  U8
n1 = n - 1, s2 = n1 & -n1, x = modPow(a, n1 / s2, n);

  if (x
== 1 || x == n1) 
return false;

  for (;
s2 > 1; s2 >>= 1)

  {

    x
= modMultiply(x, x, n);

    if (x
== 1) 
return true;

    if (x
== n1) 
return false;

  }

  return true;

}

U8
random(U8 high)

{

  // http://www.cppreference.com/wiki/c/other/rand

  return (U8)(high
* (
rand()
/ (
double)RAND_MAX));

}

// http://en.wikipedia.org/wiki/Miller-Rabin_primality_test

//
n, an integer to be tested for primality

//
k, a parameter that determines the accuracy of the test

bool probablyPrime(U8
n, 
int k)

{

  if (n
== 2 || n == 3) 
return 1;

  if (n
< 2 || n % 2 == 0) 
return 0;

  while (k--
> 0) 
if (witness(random(n
- 3) + 2, n)) 
return false;

  return true;

}

bool isPrime(int n)

{

  return probablyPrime(n,
2);

}

int outEven(int primes[], int n)

{

  int i,
p, q;

  for (i
= 0; (p = primes[i]) != 0; i++)

    if (isPrime(q
= n - p))

      return printf("%d
%d"
,
p, q);

  return printf("error:%d",
n);

}

int main(void)

{

  int t,
n, *primes = getPrimes(PRIME_MAX);

  srand(time(NULL));

  scanf("%d",
&t);

  while (t--
> 0)

  {

    scanf("%d",
&n);

    if (isPrime(n)) printf("%d",
n);

    else if ((n
& 1) == 0) outEven(primes, n);

    else if (isPrime(n
- 2)) 
printf("2
%d"
,
n - 2);

    else printf("3
"
),
outEven(primes, n - 3);

    puts("");

  }

  return 0;

}

上述程序分析如下:

  • 根据哥德巴赫猜想,充分大的偶数 n = p + q,这里 p <= q 是素数。我们猜测当 n <= 109 时,p < 104。第 8 行就是定义 p 的最大值。
  • 根据素数定理,我们知道 104 以内的素数有 1229 个。第 9 行就是定义程序中要用到的素数的个数。
  • 第 17 到 26 行的 getSieve 函数用埃拉托斯特尼筛法筛选出素数。
  • 第 28 到 36 行的 getPrimes 函数从筛中取出这些素数。
  • 第 38 到 79 行的一系列函数最终是为了 probablyPrime 函数,用于检测素数。请参见我在2010年7月写的随笔:【算法】米勒-拉宾素性检验
  • 第 81 到 84 行的 isPrime 函数调用 probablyPrime 函数来检测素数。
  • 第 86 到 93 行的 outEven 函数对大于 2 的偶数验证哥德巴赫猜想,即输出一对素数 p 和 q。
  • 第 95 到 110 行是 main 函数。其中:
  • 第 103 行处理 n 是素数的情况,直接输出该素数(包括素数 2,所以 outEven 函数处理的偶数肯定大于 2)。
  • 第 104 行对大于 2 的偶数输出一对素数(通过调用 outEven 函数,强哥德巴赫猜想)。
  • 第 105 行处理大于 5 的奇数能够分解为 2 和另外一个素数的和的情况(注意不要遗漏这个情形!)。
  • 第 106 行处理大于 5 的奇数的其他情况,首先输出一个 3,然后调用 outEven 函数处理偶数 n - 3 (弱哥德巴赫猜想)。

上述程序在 Timus Online Judge 网站的运行时间是 0.015 秒。

版权声明:本文为博主http://www.zuiniusn.com 原创文章,未经博主允许不得转载。

时间: 2024-11-09 08:01:37

【算法】验证哥德巴赫猜想的相关文章

循环-04. 验证“哥德巴赫猜想”

循环-04. 验证“哥德巴赫猜想”(20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 徐镜春(浙江大学) 数学领域著名的“哥德巴赫猜想”的大致意思是:任何一个大于2的偶数总能表示为两个素数之和.比如:24=5+19,其中5和19都是素数.本实验的任务是设计一个程序,验证20亿以内的偶数都可以分解成两个素数之和. 输入格式: 输入在一行中给出一个(2, 2 000 000 000]范围内的偶数N. 输出格式: 在一行中按照格式

验证哥德巴赫猜想,每个大于等于4的偶数都可以表示成2个素数之和

验证哥德巴赫猜想,每个大于等于4的偶数都可以表示成2个素数之和. 1 #define _CRT_SECURE_NO_WARNINGS 2 3 #include<stdio.h> 4 #include<stdlib.h> 5 6 int isou(int num)//1代表偶数,0代表奇数 7 { 8 if (num % 2 == 0) 9 { 10 return 1; 11 } 12 else 13 { 14 return 0; 15 } 16 } 17 18 int sushu(

循环-04. 验证“哥德巴赫猜想”(20)

1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 bool isPrime(long n){ 5 int i; 6 for(i=2;i<=sqrt(n);++i) 7 if(n%i==0) 8 break; 9 if(n>1&&i>sqrt(n)) 10 return true; 11 else 12 return false; 13 } 14 int main(){ 1

用C语言来验证哥德巴赫猜想(定义的是int型)

哥德巴赫猜想: 如果任意一个大于6的偶数都可以写成两个素数之和.就将其称为符合哥德巴赫猜想. #include<stdio.h> #include<math.h> /// <summary> /// 判断一个数是否是素数 /// </summary> /// <param name="intNum">要判断的数</param> /// <returns>如果是,返回true,否则,返回false<

40.验证哥德巴赫猜想:一个大于2的偶数总可以分解成两个素数的和

//1.输入一个偶数.判断是否为偶数 //2.若是,求出小于其的所有素数 //3.将它们求和 //4.验证是否满足哥德巴赫猜想 #include<iostream> #include<cmath> using namespace std; int Sushu(int); int main() { int n,k,q; int a[1000]; begin: cout<<"please input an even number(偶数):"<<

Python验证哥德巴赫猜想

今天看到百度知道有人问如何验证1000以内的数符合哥德巴赫猜想,就写了一个 感觉超过10000时有点慢啊,和java比起来效率差了点,希望高手能给优化下 #!/usr/bin/env python __author__ = '淮南霏霏' """ 脚本编写环境python 3.4.2 哥德巴赫猜想 简单验证 """ import math class Goldbach: """ 哥德巴赫猜想:任一大于2的偶数都可写成两

编程验证哥德巴赫猜想

1.什么是哥德巴赫猜想 在1742年给欧拉的信中哥德巴赫提出了以下猜想:任一大于2的整数都可写成三个质数之和.因现今数学界已经不使用"1也是素数"这个约定,原初猜想的现代陈述为:任一大于5的整数都可写成三个质数之和.欧拉在回信中也提出另一等价版本,即任一大于2的偶数都可写成两个质数之和.今日常见的猜想陈述为欧拉的版本.把命题"任一充分大的偶数都可以表示成为一个素因子个数不超过a个的数与另一个素因子不超过b个的数之和"记作"a+b".1966年陈景

c语言验证哥德巴赫猜想(从4开始 一个偶数由两个质数之和)

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <math.h> 4 5 int isit(int num) 6 { 7 int i; 8 int flag = 1;//表述为素数 9 if(num==2) 10 { 11 return 1; 12 }else if(num==3) 13 { 14 return 1; 15 }else if(num<=1) 16 { 17 return 0; 18 }el

OJ刷题之《验证哥德巴赫猜想》

题目描述 写一个函数gotbaha, 验证"每个不小于6的偶数都是两个奇素数之和",输入一个不小于6的偶数n,找出两个素数,使它们的和为n. 输入 输入一个不小于6的偶数n 输出 找出两个为素数,使它们的和为n. 样例输入 80 样例输出 80=7+73 提示 主函数已给定如下,提交时不需要包含下述主函数 /*  C代码  */ int main() { int n; int gotbaha(int); int prime(int); scanf("%d",&