POJ 2262 Goldbach's Conjecture (求解素數的一般篩和線性篩)

_TCgogogo_發表於2015-08-03


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;
            }
        }   
    }
}




相關文章