문제
- 골드바흐의 추측: 2보다 큰 짝수는 두 소수의 합으로 나타낼 수 있다.
짝수 N을 두 소수의 합으로 나타내는 표현을 골드바흐 파티션이라고 한다. 짝수 N이 주어졌을 때, 골드바흐 파티션의 개수를 구해보자. 두 소수의 순서만 다른 것은 같은 파티션이다.
입력
첫째 줄에 테스트 케이스의 개수 T (1 ≤ T ≤ 100)가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 N은 짝수이고, 2 < N ≤ 1,000,000을 만족한다.
출력
각각의 테스트 케이스마다 골드바흐 파티션의 수를 출력한다.
예제
나의 풀이1
max = 1000000
dic = {i : True for i in range(2, max + 1)}
for i in range(2, int(max**0.5) + 1):
cnt = 2
while i * cnt <= max:
if dic[i*cnt]:
dic[i*cnt] = False
cnt += 1
T = int(input())
for _ in range(T):
num = int(input())
nums = []
for i in range(2, num + 1):
if dic[i]:
nums.append(i)
cnt = 0
for j in range(len(nums)):
for k in range(j, len(nums)):
if nums[j] + nums[k] == num:
cnt += 1
print(cnt)
- 입력값의 최댓값을 길이로 가지는 딕셔너리를 만들어서 에라토스테네스의 체를 사용해 소수인지를 판별했다.
- 그후 각각의 입력값마다 해당하는 소수를 리스트에 담아서 모든 경우의 수를 실행해서 카운트를 셌다.
- 이 풀이는 당연하게도 시간초과로 실패했다.
나의 풀이2
import sys
input = sys.stdin.readline
max = 1000000
dic = {i : True for i in range(2, max + 1)}
for i in range(2, int(max**0.5) + 1):
if dic[i]:
for j in range(i * 2, max + 1, i):
dic[j] = False
T = int(input())
for _ in range(T):
N = int(input())
cnt = 0
for i in range(2, N // 2 + 1):
if dic[i] and dic[N-i]:
cnt += 1
print(cnt)
- 동일하게 딕셔너리를 사용하지만 입력값마다 골드바흐 파티션의 개수를 탐색하는 부분을 수정했다.
- 입력값의 절반만 for문을 실행해서 개수를 카운트한다.
- 예를 들면 `N`이 `10`이고 `i`가 `3`일 때, `i`와 `N-i`가 소수라면, 즉 `3`과 `7`이 소수라면 골드바흐 파티션에 해당한다.
- 이렇게 정수 `N`을 절반으로 나눠서 양 끝에서부터 하나씩 탐색한다.
- 하지만 이 풀이도 시간초과로 실패했다.
나의 풀이3
import sys
input = sys.stdin.readline
max = 1000000
nums = [True]*(max+1)
for i in range(2, int(max**0.5)+1):
if nums[i]:
for j in range(i*2, max+1, i):
nums[j] = False
T = int(input())
for _ in range(T):
N = int(input())
cnt = 0
for i in range(2, N//2+1):
if nums[i] and nums[N-i]:
cnt += 1
print(cnt)
- 딕셔너리가 아닌 리스트를 사용했다.
- 이 풀이로 드디어 테스트를 통과할 수 있었다.
- 딕셔너리가 해시테이블을 사용하기 때문에 무조건 리스트보다 빠를 거라고 생각했었는데 아니었다. 숫자를 인덱스로 다루는 경우에는 리스트가 메모리적으로 효율적이고 속도도 빠르다고 한다.