들어가며
약 2개월 이라는 기간을 두고 총 두 번 풀었던 문제인데, 수열을 다룰 줄 안다면 훨씬 쉽게 해결 가능한 문제이다.
문제 풀이
문제에서 최종적으로 요구하는 사항을 정리해보면, x에서 y로 이동하기 위한 공간이동 장치의 최소 작동 횟수를 찾는 것이다. 단, 아래의 조건을 만족시켜야 하는데, 이 중에서 세 번째 조건이 문제의 핵심 포인트라고 할 수 있다.
- 공간 이동 장치를 처음 작동시킬 때 이동 가능한 범위는 -1, 0, 1 광년이다.
- 공간 이동 장치로 이동한 거리를 k 광년이라고 할 때, 다음에 이동할 수 있는 거리의 범위는 k-1, k, k+1 광년이다.
- y에는 반드시 1 광년 만큼만 이동해서 도착해야 한다.
만약, X가 1, y가 6으로 주어질 때로 가정해보자. 먼저, x에서 y로 이동하기 위한 총 이동거리(y - x)는 5광년이다. 또한, 공간이동 장치를 처음 작동시킬 때 이동 가능한 범위는 -1, 0, 1인데, 문제에서는 x에서 y로의 이동 즉, 양의 방향으로 이동해야 하므로 이동 가능한 범위는 1 광년만 유효하게 된다. 따라서, 처음 장치를 작동시킬 때에는 1 광년만큼 이동하고, 다음 공간이동 장치의 범위는 0, 1, 2가 된다.
이동한 거리 | 다음 이동 가능 범위 | 남은 이동 거리 |
---|---|---|
1 광년 | 0, 1, 2 | 4 광년 |
공간이동 장치를 최소한으로 작동시켜야 하므로 두 번째 이동 거리는 2광년으로 하면, 다음 공간이동 장치의 범위는 1, 2, 3이 된다.
이동한 거리 | 다음 이동 가능 범위 | 남은 이동 거리 |
---|---|---|
2 광년 | 1, 2, 3 | 2 광년 |
이제 남은 이동 거리가 2 광년 남았다. 그렇다면 이동 가능 범위 중 2 광년으로 이동하면 될까? 절대 그렇지 않다.그 이유는 위에서 주어진 조건 중 세 번째 조건에 따라 y에 도착하기 전에는 반드시 1 광년 만큼만 이동해서 도착해야 하므로 1 광년 만큼만 이동해야 하기 때문이다. 즉, 1 광년 만큼 이동하여 다음 장치의 이동 가능 범위를 0, 1, 2로 만들고, 마지막 이동 시점에 1 광년 만큼 이동하면 세 번째 조건을 충족시킬 수 있다.
이동한 거리 | 다음 이동 가능 범위 | 남은 이동 거리 |
---|---|---|
1 광년 | 0, 1, 2 | 1 광년 |
1 광년 | 0, 1, 2 | 0 광년 (도착) |
문제의 내용을 이해했다면 x, y 값으로만 작동 횟수를 알아내는 규칙성을 찾아야 한다. 위에서 살펴본 내용을 바탕으로 아래와 같이 테스트 케이스를 작성한 끝에 몇 가지 규칙을 찾아내었다.
총 이동 거리(y - x) | 이동한 내역 | 작동 횟수 |
---|---|---|
1 | 1 | 1 |
2 | 1, 1 | 2 |
3 | 1, 1, 1 | 3 |
4 | 1, 2, 1 | 3 |
5 | 1, 2, 1, 1 | 4 |
6 | 1, 2, 2, 1 | 4 |
7 | 1, 2, 2, 1, 1 | 5 |
8 | 1, 2, 2, 2, 1 | 5 |
9 | 1, 2, 3, 2, 1 | 5 |
10 | 1, 2, 3, 2, 1, 1 | 6 |
11 | 1, 2, 3, 2, 2, 1 | 6 |
12 | 1, 2, 3, 3, 2, 1 | 6 |
위 표에서 작동 횟수가 같은 총 이동 거리의 최대값은 1, 2, 4, 6, 9, 12 ...
로 나타낼 수 있다. 이 수열의 증가분은 1, 2, 2, 3, 3, 4 ...
로 나타낼 수 있다. 즉, 작동 횟수가 같은 총 이동 거리의 최대값을 수열의 값만큼 증가시켜서 y - x가 총 이동 거리의 최대값보다 작거나 같은 시점을 찾으면 된다. 이를 코드로 나타내면 다음과 같다.
def value():
x, y = map(int, input().split())
return y - x
for _ in range(int(input())):
distance = value() # 총 이동 거리
maximum = 0 # 작동 횟수 별 총 이동 거리의 최대값
increase = 1 # 증가분
add = False # 증가 여부
count = 1 # 작동 횟수
while True:
maximum += increase # 최대값을 증가분만큼 증가
if add:
increase += 1 # 증가분 1 증가 ex) [1, 2, 2, 3, 3...]
add = not add # 증가 여부 역전화
if distance <= maximum:
break # 총 이동 거리가 작동 횟수 별 최대값에 포함되는 경우
count += 1 # 작동 횟수 1 증가
print(count)
마치며
알고리즘 고수들은 피식하고 웃을 수 있지만, 나 자신이 확실히 성장했다고 느껴지는 문제라고 생각된다. 그 이유는 2개월 전에 이 문제를 풀었을 때와 지금의 접근 방식이 아예 다르기 때문이다. 기억이 가물가물할 만큼 몇 시간을 문제의 늪에 빠져서 허우적대다가 결국은 풀었었지만 명확하게 설명은 하지 못할 정도였기 때문이다. 달리 말하자면, 찍어 맞춘 문제였다. 시간이 지나 이 문제를 다시 보니 보이지 않던 명확한 규칙이 보이고, 그 규칙을 어떻게 코드로 옮겨야 할 지 이제는 조금 알 것 같다는 느낌에 자신있게 문제를 풀었다.
'Algorithm > Baekjoon' 카테고리의 다른 글
1316번(그룹 단어 체커) 파이썬(Python) 풀이 공유 (0) | 2021.09.30 |
---|---|
1193번(분수 찾기) 파이썬(Python) 풀이 공유 (0) | 2021.09.30 |
Baekjoon #1744 - 수 묶기 (0) | 2021.03.26 |
Baekjoon #13305 - 주유소 (0) | 2021.03.25 |
Baekjoon #1715 - 카드 정렬하기 (0) | 2021.03.25 |