[백준] 6588번 골드바흐의 추측
- 알고리즘/백준
- 2020. 6. 25. 16:11
문제
1742년, 독일의 아마추어 수학가 크리스티안 골드바흐는 레온하르트 오일러에게 다음과 같은 추측을 제안하는 편지를 보냈다.
4보다 큰 모든 짝수는 두 홀수 소수의 합으로 나타낼 수 있다.
예를 들어 8은 3 + 5로 나타낼 수 있고, 3과 5는 모두 홀수인 소수이다. 또, 20 = 3 + 17 = 7 + 13, 42 = 5 + 37 = 11 + 31 = 13 + 29 = 19 + 23 이다.
이 추측은 아직도 해결되지 않은 문제이다.
백만 이하의 모든 짝수에 대해서, 이 추측을 검증하는 프로그램을 작성하시오.
입력
입력은 하나 또는 그 이상의 테스트 케이스로 이루어져 있다. 테스트 케이스의 개수는 100,000개를 넘지 않는다.
각 테스트 케이스는 짝수 정수 n 하나로 이루어져 있다. (6 ≤ n ≤ 1000000)
입력의 마지막 줄에는 0이 하나 주어진다.
출력
각 테스트 케이스에 대해서, n = a + b 형태로 출력한다. 이때, a와 b는 홀수 소수이다. 숫자와 연산자는 공백 하나로 구분되어져 있다. 만약, n을 만들 수 있는 방법이 여러 가지라면, b-a가 가장 큰 것을 출력한다. 또, 두 홀수 소수의 합으로 n을 나타낼 수 없는 경우에는 "Goldbach's conjecture is wrong."을 출력한다.
거의 한달만에 푼것 같다. 이 문제를
이 문제를 풀기 위해서는 한 가지 조건이 필요한데
그건 바로 소수를 구하는 아리스토텔레스의 체를 이용하는 방법이다.
이 방법은 단순하게 생각하면
i < n으로 생각하기 쉽지만
이렇게 문제를 풀면 시간 초과가 발생한다.
하는수 없이 다른 방법을 선택해서 이 문제를 해결해야 만했다.
그리고 나서 소수인 숫자를 구하고
구하려는 값과 이 소수를 뺀 값을
다시 소수인지 확인하는 로직을 만들었다.
#include <bits/stdc++.h>
using namespace std;
bool suso(int n) {
for(int i = 2;i*i<n;i++) {
if (n%i == 0) {
return false;
}
}
return true;
}
int main(void) {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
while(true) {
int n;
bool flag = true;
cin >> n;
if (n == 0) {
return 0;
}
for(int i = 3; i<=n;i+=2) {
int a = i;
if (suso(a)) {
int b = n - a;
if (suso(b) && !(b%2 == 0)) {
cout << n << " = " << a << " + " << b << "\n";
flag = false;
break;
}
}
}
if (flag) {
cout << "Goldbach's conjecture is wrong." <<"\n";
}
}
}
문제에서 b-a가 가장 큰 값을 선택하라고 했다.
이 말은 즉, a가 작을때 발생된다는 의미와 같다.
현재 위 코드로 봤을 때, 무조건 b가 a보다 크게 나온다.
왜냐하면 처음 이 조건을 만족했을때 break로 탈출하기 때문이다.
마지막으로 flag의 역할은
만약 골드바흐가 틀렸다는 가정하에 만들었다.
flag = false는 죽은 코드나 다름없지만...
가독성을 위해 살려 뒀다.
그러면 n까지 전부 다 돌았는데도 만족하는 값이 없다면
위 문장이 리턴 된다.
#include <stdio.h>
bool isPrime[1000003] = { 1, };
void sieve(int N) {
for (int i = 2; i <= N; i++)
isPrime[i] = true;
for (int cur = 2; cur <= N; cur++) {
if (!isPrime[cur])
continue;
for (int i = 2 * cur; i <= N; i += cur)
isPrime[i] = false;
}
}
int main(void) {
sieve(1000000);
while (true) {
int n;
scanf("%d", &n);
if (n == 0)
return 0;
for (int i = 3; ; i += 2) {
if (isPrime[i] && isPrime[n - i]) {
printf("%d = %d + %d\n", n, i, n - i);
break;
}
}
}
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 14888번 연산자 끼워넣기 (0) | 2020.06.27 |
---|---|
[백준] 11048번 이동하기 (0) | 2020.06.26 |
[백준] 1049번 기타줄 (0) | 2020.06.22 |
[백준] 9625번 BABB번 (0) | 2020.06.21 |
[백준] 2023번 신기한 소수 (0) | 2020.06.21 |