https://www.acmicpc.net/problem/2470
나의 생각은..
- 모든 입력을 받고나서 정렬하고 음수 양수를 각자의 배열로 분리한다.
- 음수 하나를 선택하고 해당 음수와 더해질때 0이 되는 숫자인 양수를 찾기위해 -1을 곱해서 해당 숫자를 이분 탐색 시도한다.
- 이분 탐색을 한다면 동일한 숫자는 못찾아와도 근처의 숫자까지는 시도 후 그 값을 반환 할 것이라는 판단에서 기안했다.
- 그럼 답에 그나마 가까운 이 내용와 비교하고 이 내용의 합산에 따라 0에 이전 저장값보다 가깝다면 갱신한다.
문제는
5
-100 1 2 3 4
하면 개 박살이 났다. 그래서 다른 사람들 코드를 보니 너무 정직하게 쓴 걸 통과하는걸 보고 너무 나한테 속상했다.
다른 사람 코드의 아이디어는 이렇다.
- 모든 입력을 받고나서 정렬하고, 첫 기준 점은 최대로 나올 수 있는(20억쯤) 수와 min 비교를 한다.
- 여기서는 입력을 정렬한 배열을 가리키는 포인터는 맨 처음과 맨 끝 두 개로 하기로 한다.
- 그냥 min이 아닌 절댓값 상에서의 min을 세야하니 0에서 떨어진 거리가 적으면 적을수록 해당 수로 갱신 되게 된다.
- 그리고 절댓값으로 변환하기 전의 수치를 0보다 큰지 아닌지를 보면, 포인터를 조정해서 수를 조정해야 함을 알게 된다.
- 처음에서 시작한 포인터의 위치 조정 : 반드시 결과가 증가한다
- 끝에서 시작한 포인터의 위치 조정 : 반드시 결과는 감소한다
- 결국에는 0을 왔다갔다 거리지만 0에 도착 할 수도있고 그 언저리에 있을 수도 있는 두 조합을 찾는 코드였다.
개잘하내.
실패 코드
import sys
# 양수나 음수 쪽 배열에서 아이템을 하나 잡고 남은 한쪽에서 제일 적절한 수를 찾는데 의의를 갖는다..
# 예를 들어 -2 입장에서 3 4 5 6 7 8 9를 찾아야하면 당연히 찾을 값은 2가 될 것이다.
# 그럼 양수 입장에서 2를 찾는 이분 탐색을 시도 하는 것이다.
# 3 4 5 [6] 7 8 9는 너무 크니 범위를 줄인다.
# 3 4 5 6
# 3 [4] 5 6 여전히 크다.
# 3
# [3] 3은 여전히 크고 찾을 수는 없었다. 하지만 찾고자하는 2에는 제일 가깝다.
# 보통의 이분 탐색이라면 검색 실패지만 유사 치를 찾는 것이니 이건 제일 적절하다.
# 이런식으로 음수에서 값을 pick 한다음 가장 적합한 값을 찾는다.
# 0에 가까운 경우는 음수, 양수, 값 순으로 값을 갱신하고 값을 기준으로 이 튜플이 변경되도록 한다.
# 마지막엔 음수, 양수 순으로 출력하고 프로그램이 끝난다.
caseCnt = int(sys.stdin.readline())
numField = list(map(int, sys.stdin.readline().strip().split()))[:caseCnt]
onlyPlus = []
onlyMinus = []
ansPlus = 0
ansMinus = 0
ans = 1000000000
def binarySearch(str, end, target):
lastestVisited = 0
while(str <= end):
mid = (str + end) // 2
if(onlyPlus[mid] == target):
lastestVisited = onlyPlus[mid]
return lastestVisited
if(onlyPlus[mid] > target):
end = mid - 1
else:
str = mid + 1
lastestVisited = onlyPlus[mid]
if(str > end):
return lastestVisited
numField.sort()
for i in range(len(numField)):
if(numField[i] > 0):
onlyPlus.append(numField[i])
else:
onlyMinus.append(numField[i])
if(len(onlyMinus) == 0):
ansMinus = onlyPlus[0]
ansPlus = onlyPlus[1]
ans = ansMinus + ansPlus
elif (len(onlyPlus) == 0):
ansPlus = onlyMinus[len(onlyMinus) - 1]
ansMinus = onlyMinus[len(onlyMinus) - 2]
ans = abs(ansMinus + ansPlus)
else:
for i in range(len(onlyMinus)):
# 음수 하나 픽, 이거에 제일 적합한 음수 찾기.
# 어쨌든 이분 탐색은 제일 가까운 답을 뱉게 된다.
targetNum = -1 * onlyMinus[i]
expectedNum = binarySearch(0, len(onlyPlus) - 1, targetNum)
tmpAns = abs(targetNum - expectedNum)
if(ans > tmpAns):
ans = tmpAns
ansMinus = onlyMinus[i]
ansPlus = expectedNum
# 그 답과 더해서 나온 값이 최저치라면, 답을 갱신해야한다.
# 답의 저장 양식은 3개이다 : ansPlus, ansMinus, ans
# 문제 :
# minus가 아예 없거나 plus가 아예 없는 경우를 고려해야한다.
for i in range(len(onlyPlus) - 1):
tmpMin = onlyPlus[i]
tmpMax = onlyPlus[i + 1]
tmpAnswer = abs(tmpMin + tmpMax)
if(ans > tmpAnswer):
ans = tmpAnswer
ansMinus = tmpMin
ansMax = tmpMax
for i in range(len(onlyMinus) - 1, 1, -1):
tmpMin = onlyMinus[i - 1]
tmpMax = onlyMinus[i - 2]
tmpAnswer = abs(tmpMin + tmpMax)
if(ans > tmpAnswer):
ans = tmpAnswer
ansMinus = tmpMin
ansMax = tmpMax
print(f"{ansMinus} {ansPlus}")
정답 처리 코드
import sys
caseCnt = int(sys.stdin.readline())
numField = list(map(int, sys.stdin.readline().strip().split()))[:caseCnt]
numField.sort()
startIdx = 0
endIdx = caseCnt - 1
numA = 1000000000
numB = 1000000001
while startIdx != endIdx:
if(abs(numField[startIdx] + numField[endIdx]) < abs(numA + numB)):
numA = numField[startIdx]
numB = numField[endIdx]
if(numField[startIdx] + numField[endIdx] < 0):
startIdx += 1
else:
endIdx -= 1
print(f"{numA} {numB}")
'문제풀이' 카테고리의 다른 글
[PY] 2493 : 탑 (0) | 2025.03.25 |
---|---|
[PY] 8983 : 사냥꾼 (0) | 2025.03.25 |
[PY] 17608 : 막대기 (0) | 2025.03.24 |
[PY] 9012 : 괄호 (0) | 2025.03.24 |
[PY] 10773 : 제로 (0) | 2025.03.24 |