Python/Python 문제

백준) 골드바흐 파티션

서영환 2024. 8. 9. 11:09

문제 ) 골드바흐 파티션

 

해당 문제에서 요구하는 사항은 짝수 숫자 N을 주어 졌을 때 N 보다 작은 소수의 두 합이 N이 되는 가짓수를 출력해 달라는 것이다. 이때 3 + 5, 5 + 3은 하나로 취급 한다.

 

문제 지문 자체는 어렵지 않으나 이제 어떤 식으로 해서 가짓수를 출력해야 될지가 문제였었다.

차근차근 고민은 및 손으로 규칙이 없나 찾아보다가

6 = 1

8 = 1

10 = 2

12 = 1

이라는 테스트 케이스를 보고 곰곰히 생각을 해보았다

6 = 3 + 3, (2 + 4, 2는 소수이지만 4는 소수가 아니다)

8 = 5 + 3, (2 + 6, 2는 소수이지만 6은 소수가 아니다)

10 = 7 + 3, 5 + 5, ( 2 + 8, 2는 소수이지만 8은 소수가 아니다)

12 = 7 + 5 , (11 + 1, 1은 소수가 아니므로 탈락)

 

해당 식을 적어보니 확실히 규칙이 보였다. 구하고자하는 N - sosu = min_sosu 가 되면 된다

만약 N - sosu != min_sosu이면 카운트를 안하면 된다.

 

이렇게 일단 숫자의 가짓수를 체크에 대한 규칙을 찾았고 이제 소수를 구하기만 하면 이문제는 해결이 될걸로 생각이 된다.

 

이 때까지 소수를 구하는 문제를 많이 풀기도하여 쉽게 생각을 하고 소수를 구하는 식을 작성한 뒤 문제를 풀었는데 어찌된 영문이지 시간 초과를 하게 되었다.

 

더보기

이떄까지 내가 주로 사용한 소수 구한 코드

dp = [0] * 1000001
dp[2] = 1
for i in range(2, 1000001):
    is_ok = True
    for j in range(2, int(i ** 0.5) + 1):
        if i % j == 0:
            is_ok = False
            break
    if is_ok:
        dp[i] = 1

 

전체 코드

import sys
dp = [0] * 1000001
dp[2] = 1
for i in range(2, 1000001):
    is_ok = True
    for j in range(2, int(i ** 0.5) + 1):
        if i % j == 0:
            is_ok = False
            break
    if is_ok:
        dp[i] = 1

T = int(sys.stdin.readline().strip())
for _ in range(T):
    N = int(sys.stdin.readline().strip())
    count = 0
    visited = {}
    for idx in range(N):
        if dp[idx] == 0: continue
        if dp[N - idx] == 1 and N - idx >= idx:
            count += 1

    sys.stdout.write(f'{count}\n')

 

소수구하는 식을 제외하고는 시간초가 날만한 부분이 전혀 보이지 않았다.

그렇다면 소수를 구하는 방법이 너무 오래 걸린다는 건데 이를 현재의 나로써는 생각하기 어려워 어쩔 수 없이 구글링을 통하여 좀더 빠른 소수구하는 방식을 손에 넣을 수 있었다.

 

더보기

향상된 소수 공식 코드

p = [1] * 1000001
sosu_list = []
for i in range(2, 1000001):
    if dp[i] == 1:
        sosu_list.append(i)
        for j in range(i*2, 1000001, i):
            dp[j] = 0

 

의 소수를 구하는 부분은 일단 전체 값을 일정한 값으로 통일을 한 뒤 통일한 값으로 된 자리이면 소수이고 이후 소수의 배수는 전부 다른 값으로 대체하여 중복 검사를 최대한 피하는 방식이다

 

찾은 방식으로 기존 코드의 소수 구하는 부분에 적용을 한 뒤 제출을 하니 무사히 코드가 통과됨을 확인하였다.

 

더보기

전체 코드

import sys
dp = [1] * 1000001
sosu_list = []
for i in range(2, 1000001):
    if dp[i] == 1:
        sosu_list.append(i)
        for j in range(i*2, 1000001, i):
            dp[j] = 0

T = int(sys.stdin.readline().strip())
for _ in range(T):
    N = int(sys.stdin.readline().strip())
    count = 0
    visited = {}
    for sosu in sosu_list:
        if sosu > N: break
        if dp[N - sosu] == 1 and N - sosu >= sosu:
            count += 1

    sys.stdout.write(f'{count}\n')

 

다음에는 구글링 없이도 내가 코드를 짤 수 있게 해당 문제는 나의 오답노트 링크로 남겨 놓고 추후 시간이 지나면 다시 풀어봐야 할거 같다