POJ 2262 Goldbach's Conjecture (求解素数的一般筛和线性筛)


Goldbach's Conjecture
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 40944   Accepted: 15664

Description

In 1742, Christian Goldbach, a German amateur mathematician, sent a letter to Leonhard Euler in which he made the following conjecture:
Every even number greater than 4 can be
written as the sum of two odd prime numbers.

For example:
8 = 3 + 5. Both 3 and 5 are odd prime numbers.
20 = 3 + 17 = 7 + 13.
42 = 5 + 37 = 11 + 31 = 13 + 29 = 19 + 23.

Today it is still unproven whether the conjecture is right. (Oh wait, I have the proof of course, but it is too long to write it on the margin of this page.)
Anyway, your task is now to verify Goldbach's conjecture for all even numbers less than a million.

Input

The input will contain one or more test cases.
Each test case consists of one even integer n with 6 <= n < 1000000.
Input will be terminated by a value of 0 for n.

Output

For each test case, print one line of the form n = a + b, where a and b are odd primes. Numbers and operators should be separated by exactly one blank like in the sample output below. If there is more than one pair of odd primes adding up to n, choose the pair where the difference b - a is maximized. If there is no such pair, print a line saying "Goldbach's conjecture is wrong."

Sample Input

8
20
42
0

Sample Output

8 = 3 + 5
20 = 3 + 17
42 = 5 + 37

Source

Ulm Local 1998

题目链接:http://poj.org/problem?id=2262

题目大意:把一个数分成两个奇素数的和,要求b-a的差最大

题目分析:题是水题,从小到大枚举即可,主要是借这道题说明一下求解素数的两个筛法

普通的素数筛时间复杂度O(nlogn)
void get_prime()  
{  
    memset(prime, true, sizeof(prime));  
    prime[1] = 0;  
    for(int i = 2; i * i <= MAX; i++)    
        if(prime[i])    
            for(int j = i * i; j <= MAX; j += i)    
                prime[j] = 0;  
}


线性筛时间复杂度O(n)
void get_prime()
{
    pnum = 0;
    memset(prime, true, sizeof(prime));
    prime[0] = false;
    prime[1] = false;
    for(int i = 2; i < MAX; i++)
    {
        if(prime[i])
            p[pnum ++] = i;
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)
        {
            prime[i * p[j]] = false;
            if(i % p[j] == 0)
                break;
        }
    }
}

普通筛没什么好说的,主要是线性筛的break那里,比如12这个数,在普通筛的时候12要被2和3都筛一次,显然这种多余的操作会增加时间复杂度,线性筛中一个数字只被它最小的素因子筛掉,比如12只被2筛掉,当i等于6的时候2*6==12筛掉12,这时候6%2==0可以break了,如果不break,那么6还会把18筛掉,此时是通过6*3来筛掉18,可是显然18最小的素因子是2,所以当i枚举到9的时候有9*2==18,这样18就又被筛了一次,因此在i等于6的时候不用拿6去筛18,下面用公式来说明:
当prime[j]是i的因子时,设i=prime[j]*k,因为素因子从小到大枚举,所以prime[j]是i的最小素因子,此时i已经无需再去剔除prime[j']*i (j'>j) 形式的合数了,因为prime[j']*i可以写成prime[j']*(prime[j]*k)=prime[j]*(prime[j']*k),也就是说所有的prime[j']*i将会被将来的某个i'=prime[j']*k剔除掉,当前的i已经不需要了。比如先前举的实例

本题代码:
#include <cstdio>
#include <cstring>
int const MAX = 1000005;
int p[MAX];
bool prime[MAX];
int pnum;

void get_prime()
{
    pnum = 0;
    memset(prime, true, sizeof(prime));
    prime[0] = false;
    prime[1] = false;
    for(int i = 2; i < MAX; i++)
    {
        if(prime[i])
            p[pnum ++] = i;
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)
        {
            prime[i * p[j]] = false;
            if(i % p[j] == 0)
                break;
        }
    }
}

// void get_prime()  
// {  
//     memset(prime, true, sizeof(prime));  
//     prime[1] = 0;  
//     for(int i = 2; i * i <= MAX; i++)    
//         if(prime[i])    
//             for(int j = i * i; j <= MAX; j += i)    
//                 prime[j] = 0;  
// }

int main()
{
    get_prime();
    int n;
    while(scanf("%d", &n) != EOF && n)
    {
        for(int i = 3; i <= n / 2; i += 2)
        {
            if(prime[i] && prime[n - i])
            {
                printf("%d = %d + %d\n", n, i, n - i);
                break;
            }
        }   
    }
}




你可能感兴趣的:(数论,poj,素数筛)