리모컨

노영현·2023년 3월 29일
0

2023 1학기 백준

목록 보기
3/7

리모컨

이 문제를 푸는데 있어 많은 예외가 존재해 어려움을 겪었기에 풀이과정을 공유하고자 한다.

리모컨(1107번)

문제

수빈이는 TV를 보고 있다. 수빈이는 채널을 돌리려고 했지만, 버튼을 너무 세게 누르는 바람에, 일부 숫자 버튼이 고장났다.

리모컨에는 버튼이 0부터 9까지 숫자, +와 -가 있다. +를 누르면 현재 보고있는 채널에서 +1된 채널로 이동하고, -를 누르면 -1된 채널로 이동한다. 채널 0에서 -를 누른 경우에는 채널이 변하지 않고, 채널은 무한대 만큼 있다.

수빈이가 지금 이동하려고 하는 채널은 N이다. 어떤 버튼이 고장났는지 주어졌을 때, 채널 N으로 이동하기 위해서 버튼을 최소 몇 번 눌러야하는지 구하는 프로그램을 작성하시오.

수빈이가 지금 보고 있는 채널은 100번이다.

코드 1

import sys
input=sys.stdin.readline

now=100
N=int(input())
M=int(input())
cnt=len(str(N))
up,down=N,N
if M!=0:
  err=set()
  err.update(list(input().split()))
  while 1:
    if not(set(str(up))&err):
      break
    if not(set(str(down))&err):
      break
    cnt+=1
    up+=1
    down-=1

print(min(cnt,abs(now-N)))

풀이

찾으려는 N값을 기준으로 위, 아래 방향으로 탐색하며 고장난 버튼의 숫자가 포함되지 않은 채널을 찾는다. 숫자를 누르지 않고 100번에서 이동하는 경우와, 숫자를 눌러 이동하는 경우 중 횟수가 적은 것을 찾는다.
시간초과

코드 2

import sys
input=sys.stdin.readline

now=100
N=int(input())
M=int(input())
cnt=len(str(N))
up,down=N,N
if M!=0:
  err=set()
  err.update(list(input().split()))
  while 1:
    check=True
    for x in str(up):
      if x in err:
        check=False

        break
    if check:
      break
    for x in str(down):
      if x in err:
        check=False

        break
    if check:
      break
    cnt+=1
    up+=1
    down-=1

print(min(cnt,abs(now-N)))

풀이

set의 교집합이 시간이 오래 걸릴 수 있을 것이라 생각해서 for loop로 직접 돌려주는 방식으로 바꾸어 보았지만 역시 시간초과가 나왔다.
시간초과

코드 3

import sys
input=sys.stdin.readline

now=100
N=int(input())
M=int(input())
cnt=len(str(N))
up,down=N,N
if M!=0:
  err=set()
  err.update(list(input().split()))
if M!=10:
  while 1:
    if not(set(str(up))&err):
      break
    if not(set(str(down))&err):
      break
    cnt+=1
    up+=1
    down-=1

if M==10:
  print(abs(now-N))
else:
  print(min(cnt,abs(now-N)))

풀이

시간초과의 이유를 찾아냈는데 M이 10일 경우 무한루프가 돌아가서 시간초과가 나오는 것이었다. 그래서 M이 10인 경우를 예외처리하여 다시 코드를 작성하자 시간초과의 늪에서는 벗어났으나 '틀렸습니다'가 나왔다.
틀렸습니다

코드 4

import sys
input=sys.stdin.readline

now=100
N=int(input())
M=int(input())
cnt=0
up,down=N,N
if M!=0:
  err=set()
  err.update(list(input().split()))
  if M!=10:
    while 1:
      if not(set(str(down))&err):
        check='both'
        break
      if not(set(str(up))&err):
        check='up'
        break
      cnt+=1
      up+=1
      down-=1
if check=='up':
  cnt+=len(str(up))
else:
  cnt+=len(str(down))
  

if M==0:
  print(len(str(N)))
elif M==10:
  print(abs(now-N))
else:
  print(min(cnt,abs(now-N)))

풀이

기존 코드의 문제점을 찾아냈는데
cnt=len(str(N)) 라는 문장 때문에 만약 아래로 탐색한 결과의 자리수가 N의 자리수보다 작아진다면 틀린 답이 나왔다. 그래서 check라는 변수를 도입하여 아래로 탐색한 결과의 자리수가 달라질 때의 값으로 바꾸어주었다.
런타임 에러 (NameError)

코드 5

import sys
input=sys.stdin.readline

now=100
N=int(input())
M=int(input())
cnt=0
up,down=N,N
check=''
if M!=0:
  err=set()
  err.update(list(input().split()))
  if M!=10:
    while 1:
      if not(set(str(down))&err):
        check='both'
        break
      if not(set(str(up))&err):
        check='up'
        break
      cnt+=1
      up+=1
      down-=1
      if down<0:
        down=0

if check=='up':
  cnt+=len(str(up))
else:
  cnt+=len(str(down))
  

if M==0:
  print(len(str(N)))
elif M==10:
  print(abs(now-N))
else:
  print(min(cnt,abs(now-N)))

풀이

down이 0보다 작아지는 경우와 지역변수 check 범위 바꿔줬다.
틀렸습니다

코드 6

import sys
input=sys.stdin.readline

now=100
N=int(input())
M=int(input())
cnt=0
up,down=N,N
check=''
if M!=0:
  err=set()
  err.update(list(input().split()))
  if M!=10:
    while 1:
      if not(set(str(down))&err):
        check='both'
        break
      if not(set(str(up))&err):
        check='up'
        break
      cnt+=1
      up+=1
      down-=1
      if down<0:
        down=0

if check=='up':
  cnt+=len(str(up))
else:
  cnt+=len(str(down))
  

if M==0:
  print(min(abs(now-N),len(str(N))))
elif M==10:
  print(abs(now-N))
else:
  print(min(cnt,abs(now-N)))

풀이

M이 0일때에도 N이 99 or 101인 경우를 고려하지 않아서 수정해주었다.
맞았습니다!!

이렇게 고려해야 하는 케이스가 많은 경우에 여러 시행착오를 겪게 되는데 질문게시판을 이용해보는 것도 나쁘지 않다. 많은 반례 케이스들이 나와있는데 이것들을 하나씩 돌려보면서 내 코드의 문제점을 수정해 정답을 찾아냈을 때 괜한 뿌듯함을 느낄 수 있다!!

0개의 댓글