[BOJ]18112. 이진수 게임
❌code 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from collections import deque
def toggle(binary, idx): # idx 위치를 보수로 바꾼 값 반환
binary ^= (1 << idx)
return binary
def binary_game():
q = deque()
q.append(start) # 시작 지점 추가
checked = [-1] * 1024 # 인덱스의 이진수를 만들기 위한 최소 연산 횟수 기록
checked[start] = 0 # 시작 지점 초기화
while True:
cur_num = q.popleft() # 현재 이진수
if cur_num == target: # 목표 이진수 도착
return checked[cur_num]
# 한 자리 숫자를 보수로 바꾸기
for i in range(len(bin(cur_num)) - 3):
result = toggle(cur_num, i)
if 1024 <= result: # 1024 이상의 숫자는 나올 수 없음
continue
if -1 < checked[result]:
continue # 이미 확인한 숫자는 무시
checked[result] = checked[cur_num] + 1 # 연산 횟수 갱신
path[result] += path[cur_num] + [cur_num] # 디버깅용
q.append(result)
# 현재 수에 1 더하기와 현재 수에서 1 빼기
for delta in [-1, 1]:
result = cur_num + delta
if 1024 <= result: # 1024 이상의 숫자는 나올 수 없음
continue
if -1 < checked[result] or result < 0:
continue # 이미 확인한 숫자 또는 음수 무시
checked[result] = checked[cur_num] + 1 # 연산 횟수 갱신
path[result] += path[cur_num] + [cur_num] # 디버깅용
q.append(result)
start = int(input(), 2)
target = int(input(), 2)
print(binary_game())
시도
시작 이진수에서 시작해 만들어지는 모든 이진수를 십진수로 변환하여 checked
리스트에 동일한 값의 인덱스에 연산 횟수를 기록한다.
문제
IndexError
⭕code 2
1
2
3
4
5
6
def binary_game():
q = deque()
q.append(start) # 시작 지점 추가
checked = [-1] * 1000000 # 인덱스의 이진수를 만들기 위한 최소 연산 횟수 기록
checked[start] = 0 # 시작 지점 초기화
시도
시작 이진수에서 목표 이진수로 가는 과정 중 1024
이상의 숫자가 등장할 일이 없다고 생각했기에 code 1
에서 리스트의 길이를 1024
로 설정했었다. 하지만 code 1
에서 인덱스 에러가 발생해 1024
이상의 숫자로 올라간 후 다시 아래로 내려올 때 연산 횟수가 더 작은 경우가 존재할 수도 있다고 생각해 checked
리스트의 길이를 1000000
으로 늘렸다. (결과적으로 이는 불필요한 과정이었다.)
문제
특별한 이유 없이 임의의 큰 숫자 1000000
을 설정한 것이라 정확하게 필요한 길이를 구하고 싶었다. 시작 이진수에서 목표 이진수로 가는 과정 중 가능한 숫자의 최댓값을 알아내어 해당 최댓값을 통해 길이를 설정하고자 하였다.
⭕code 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from collections import deque
def toggle(binary, idx): # idx 위치를 보수로 바꾼 값 반환
binary ^= (1 << idx)
return binary
def binary_game():
q = deque()
q.append(start) # 시작 지점 추가
checked = [-1] * 1024
checked[start] = 0 # 시작 지점 초기화
path = [[] for _ in range((1 << 11) + 1)] # 디버깅용 경로 저장 리스트
while True:
cur_num = q.popleft() # 현재 이진수
if cur_num == target: # 목표 이진수 도착
path[cur_num] += [cur_num] # 디버깅용
return checked[cur_num]
for _ in range(3):
# 한 자리 숫자를 보수로 바꾸기
for i in range(len(bin(cur_num)) - 3):
result = toggle(cur_num, i)
if 1024 <= result: # 1024 이상의 숫자는 나올 수 없음
continue
if -1 < checked[result]:
continue # 이미 확인한 숫자는 무시
checked[result] = checked[cur_num] + 1 # 연산 횟수 갱신
path[result] += path[cur_num] + [cur_num] # 디버깅용
q.append(result)
# 현재 수에 1 더하기와 현재 수에서 1 빼기
for delta in [-1, 1]:
result = cur_num + delta
if 1024 <= result: # 1024 이상의 숫자는 나올 수 없음
continue
if -1 < checked[result] or result < 0:
continue # 이미 확인한 숫자 또는 음수 무시
checked[result] = checked[cur_num] + 1 # 연산 횟수 갱신
path[result] += path[cur_num] + [cur_num] # 디버깅용
q.append(result)
start = int(input(), 2)
target = int(input(), 2)
print(binary_game())
시도
시작 이진수에서 목표 이진수까지 만들어지는 과정을 path
에 저장하여 이를 확인하였다. 작성한 코드에 오류가 있을 가능성도 있지만 start
와 target
을 각각 0
에서 1023
까지 설정하여 path
를 기록하였을 때 1024
가 등장하는 경우 또는 시작 이진수보다 큰 수를 거쳐 목표 이진수를 만드는 경우 중 2 ** (이진수의 길이)
이상의 값이 등장하는 경우는 찾지 못했다. 시작 이진수보다 큰 수를 거쳐 목표 이진수를 만드는 예시는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# case 1
시작 10111111 # 191
경로 11000000 # 192
목표 10000000 # 128
# case 2
시작 1011111111 # 767
경로 1100000000 # 768
목표 1000000000 # 512
# case 3
시작 10111 # 23
경로 11000 # 24
도착 10000 # 16
# case 4
시작 100111 # 39
경로 101000 # 40
도착 100000 # 32
문제 해결
이를 고려하여 checked
의 길이는 1024
로 설정하지만 if 문에서 check[result]
값을 확인할 때에 인덱스 에러가 나지 않도록 다음과 같이 코드를 추가하였다.
1
2
3
4
if 1024 <= result: # 1024 이상의 숫자는 나올 수 없음
continue
if -1 < checked[result]:
continue # 이미 확인한 숫자는 무시
요약
- 시작 이진수에서 목표 이진수로 가는 경로에 제시된 최댓값보다 큰 값이 나오는 경우는 발견되지 않았다.
- 따라서 연산 횟수를 기록할 리스트의 길이는 주어진 최댓값으로 충분하며 이를 벗어나는 값은 if 문으로 처리해 인덱스 에러를 방지할 수 있다.