문제풀이

[PY] 9020 : 골드바흐의 추측

pwerty 2025. 3. 20. 11:07

https://www.acmicpc.net/problem/9020

 

 

얘 진짜 당황스러운 문제였다. 힌트로는 에라스토테네스의 체를 제시하길래 나무위키에서 찾은 내용대로 구현을 했다.
테스트 케이스들에 대해서도 작동이 좋았으니 잘 되겠거니 하고 백준에 던졌는데,

시간 초과!!!!!!!!

그래서 주변에 묻고 힌트를 얻으려해보니 그냥 문제를 한번 다시 봐보라는 이야기를 하더라.
주어지는 입력은 짝수였고 2로 나눠도 나머지가 없다.
그럼 나눠진 숫자를 다시 더해도 내용은 같다는거고 어쨌든 두 갈래로 값이 나뉘었을 때
하나가 적어진 만큼 다른 하나가 커지면 어쨌든 내용은 똑같은 것이다.

결론은 주어지는 숫자를 가져와서 2로 나눈 다음에 소수인지 아닌지를 체크해 나간다.
소수가 아니면 숫자를 조금씩 바꾼다. 한쪽은 1을 내리고 한쪽은 1을 올린다. 그리고 가장 먼저 발견되는 숫자 쌍이 정답이다.
왜냐하면 차이가 적은 답을 가져와야 하는데, 가장 먼저 발견되는 쌍이 제일 차이가 적은 답이기 때문이다.

다음엔 더 입체적으로 문제를 볼 수 있도록 해보려고 한다.

<기존에 구상한 코드>

#past code
from math import sqrt
from sys import stdin

array = list(range(1, 10001))
squareRoot = sqrt(10000)


for i in range(int(squareRoot)):
    if i == 0 or i == 1:
        continue
    isNotPrime = False
    for j in range(2, i):
        # range가 i라는건 어쨌든 i - 1 까지인거니까 의미있는 소수 판정이 가능하다
        if i % j == 0:
            isNotPrime = True

        if isNotPrime:
            break
        # i라는 숫자 하나에 대해 모든 숫자를 대조해서 비교하니, 
        # 중간에 소수가 아님이 확인된다면 바로 그만 둘 수 있도록 한다.

    # 이쪽 영역에 들어오면 백프로 소수이다.
    for j in range(2, (int(squareRoot) // i) + 1):
        # squareRoot 숫자를 넘어가지 않도록 하기 위함이다. 즉 i가 7이면 sqR // i는 14가 나오겠지, 하지만 range는 해당 숫자 직전에서 끝내기 때문에
        # + 1을 끝 점에 지정한다. 그리고 * 1 이 계산되면 안되기때문에 명시적으로 2를 적는다.
        delTargetIdx = i * j - 1
        array[delTargetIdx] = -1
        # array[0] = 1이 들어있으니, 내가 뺴야하는 값에서 - 1을 해야 빼야하는 값의 위치가 잡힌다.

# 이거 array가 어쨌든 길이가 가변성이니 문제가 생길 수 있겠다.
a = 0
while a < len(array):
    if array[a] == -1:
        del array[a]
    else:
        a += 1

# 여기서 모든 소수 목록의 결과를 확인 할 수 있다.
# 에라토스 뭐시기의 체는 구현 완료

# 그럼 소수만 있는 Pool에서 전개를 해나가야한다.
# 입력된 숫자의 범위 이상 직전
    # 즉 8이 입력되면 8은 소수 7보다 크고 소수 11보다 작으니 7까지의 범위를 제한하고
    # 여기서 더해질 수 있는 모든 쌍을 얻어야한다.
    # 쌍을 얻고나면 두 차가 제일 작은 경우가 답이 된다.

caseNum = int(stdin.readline())


for i in range(caseNum):
    resultList = []
    minVal = 10000000
    minIdx = 0

    targetNum = int(stdin.readline())
    isFounded = False
    defIdx = 0

    for j in range(len(array)):
        # targetNum이랑 비교해서 범위를 찾아내야한다.
        if targetNum <= array[j]:
            isFounded = True
            defIdx = j - 1
            break

    for j in range(defIdx):
        for k in range(defIdx):
            if targetNum == array[j] + array[k]:
                resultList.append([array[j],array[k]])

    for idx, pair in enumerate(resultList, start=0):
        result = abs(pair[0] - pair[1])

        if minVal > result:
            minVal = result
            minIdx = idx

    print(str(resultList[minIdx][0]) + " " + str(resultList[minIdx][1]))

<문제 정독 후 정정된 코드>

#after code
from sys import stdin

def isPrimeNum(num):
    if num <= 1:
        return False

    if num == 2:
        return True

    for i in range(2, num):
        if num % i == 0:
            return False

    return True


caseNum = int(stdin.readline())

for i in range(caseNum):
    targetNum = int(stdin.readline())
    targetA = targetNum // 2
    targetB = targetA


    minVal = 1000000
    minIdx = 0

    while targetA != 1:
        if isPrimeNum(targetA) and isPrimeNum(targetB):
                print(str(targetA) + " " + str(targetB))
                break

        targetA -= 1
        targetB += 1