https://www.acmicpc.net/problem/9019
DSLR 성공스페셜 저지다국어
6 초 | 256 MB | 81595 | 19974 | 13065 | 20.807% |
문제
네 개의 명령어 D, S, L, R 을 이용하는 간단한 계산기가 있다. 이 계산기에는 레지스터가 하나 있는데, 이 레지스터에는 0 이상 10,000 미만의 십진수를 저장할 수 있다. 각 명령어는 이 레지스터에 저장된 n을 다음과 같이 변환한다. n의 네 자릿수를 d1, d2, d3, d4라고 하자(즉 n = ((d1 × 10 + d2) × 10 + d3) × 10 + d4라고 하자)
- D: D 는 n을 두 배로 바꾼다. 결과 값이 9999 보다 큰 경우에는 10000 으로 나눈 나머지를 취한다. 그 결과 값(2n mod 10000)을 레지스터에 저장한다.
- S: S 는 n에서 1 을 뺀 결과 n-1을 레지스터에 저장한다. n이 0 이라면 9999 가 대신 레지스터에 저장된다.
- L: L 은 n의 각 자릿수를 왼편으로 회전시켜 그 결과를 레지스터에 저장한다. 이 연산이 끝나면 레지스터에 저장된 네 자릿수는 왼편부터 d2, d3, d4, d1이 된다.
- R: R 은 n의 각 자릿수를 오른편으로 회전시켜 그 결과를 레지스터에 저장한다. 이 연산이 끝나면 레지스터에 저장된 네 자릿수는 왼편부터 d4, d1, d2, d3이 된다.
위에서 언급한 것처럼, L 과 R 명령어는 십진 자릿수를 가정하고 연산을 수행한다. 예를 들어서 n = 1234 라면 여기에 L 을 적용하면 2341 이 되고 R 을 적용하면 4123 이 된다.
여러분이 작성할 프로그램은 주어진 서로 다른 두 정수 A와 B(A ≠ B)에 대하여 A를 B로 바꾸는 최소한의 명령어를 생성하는 프로그램이다. 예를 들어서 A = 1234, B = 3412 라면 다음과 같이 두 개의 명령어를 적용하면 A를 B로 변환할 수 있다.
1234 →L 2341 →L 3412
1234 →R 4123 →R 3412
따라서 여러분의 프로그램은 이 경우에 LL 이나 RR 을 출력해야 한다.
n의 자릿수로 0 이 포함된 경우에 주의해야 한다. 예를 들어서 1000 에 L 을 적용하면 0001 이 되므로 결과는 1 이 된다. 그러나 R 을 적용하면 0100 이 되므로 결과는 100 이 된다.
입력
프로그램 입력은 T 개의 테스트 케이스로 구성된다. 테스트 케이스 개수 T 는 입력의 첫 줄에 주어진다. 각 테스트 케이스로는 두 개의 정수 A와 B(A ≠ B)가 공백으로 분리되어 차례로 주어지는데 A는 레지스터의 초기 값을 나타내고 B는 최종 값을 나타낸다. A 와 B는 모두 0 이상 10,000 미만이다.
출력
A에서 B로 변환하기 위해 필요한 최소한의 명령어 나열을 출력한다. 가능한 명령어 나열이 여러가지면, 아무거나 출력한다.
예제 입력 1 복사
3
1234 3412
1000 1
1 16
예제 출력 1 복사
LL
L
DDDD
BFS로 풀었다.
대표적인 BFS문제로는 길찾기가 있는데 갈 수 있는 방향이 네군대라고 한다면, 네 방향 전부 탐색해보고 갈수있는 방향만 다시 또 탐색하는 방법과 유사하다고 생각한다.
일단 4가지 연산이 나온다.
D : 수를 두배 증가시킨다. 10000이 넘어간다면 10000으로 나눈 나머지를 저장한다.
S : 수를 1 감소시킨다. 만약 0에서 더 빼려고 한다면 9999로 저장한다. 즉, 음수라면 9999로 저장하면 된다.
L : 수를 왼쪽으로 회전시킨다. 1234 -> 2341
R : 수를 오른쪽으로 회전시킨다. 1234 -> 4123
이러한 네가지 연산을 들고 있는데 주의할점은 레지스터가 4자리 레지스터라는 점이다.
즉, 예를 들어 4가 저장되어있다면 레지스터에는 다음과 같이 저장된다.
d0 | d1 | d2 | d3 |
0 | 0 | 0 | 4 |
4가 아니라 0004가 저장된다는 점이다.
여기에 L,R연산을 각각하면
0004 -> 0040 -> 40
0004 -> 4000 -> 4000 으로 된다.
수를 회전시키기 위해서 다음과 같은 연산이 있다는 점을 배웠다.
#예시
n = 1234
str = str(n)
n = int(str[1:] + str[:1]) #왼쪽으로 회전
n = int(str[-1:] + str[:-1]) #오른쪽으로 회전
몇번 썼지만, 인덱스 연산에서 시간이 오래 걸린다는것을 알아 일단 접어두고 다른 방법으로 작성하였다.
그리고 중첩 조건문을 한줄로 처리하는 방법도 이번기회에 알게 되었다.
#i가 0에서 3까지 증가한다고 가정하면
if i == 0:
print(0)
elif i == 1:
print(1)
elif i == 1:
print(2)
else
print(3)
#이것을 다시 하면
print(0 if i == 0 else 1 if i == 1 else 2 if i == 2 else 3)
#으로 쓸 수 있다.
각 연산을 제대로 구현하고, BFS알고리즘을 적용해 모든 케이스에 맞춰 방문을 한다.
그리고 queue에 넣을 값은 [값, '반복된 연산을 저장하는 문자열'] 과 같은 식으로 넣었다.
코드는 다음과 같다.
#9019 DSLR
from collections import deque
import sys
def bfs(n, target, visited):
q = deque([[n,'']])
visited[n] = True
i = 0
while q:
n = q.popleft()
if n[0] == target:
return n[1]
d = n[0]*2 % 10000
s = n[0]-1 if n[0]-1 >= 0 else 9999
d1,d2,d3,d4 = n[0] // 1000 , (n[0] //100) % 10, (n[0]//10)%10, n[0]%10
l = d2*1000 + d3*100 + d4*10 + d1
r = d4*1000 + d1*100 + d2*10 + d3
dir = [d,s,l,r]
for i in range(4):
if not visited[dir[i]]:
arr = n[1] + 'D' if i == 0 else n[1] + 'S' if i == 1 else n[1] + 'L' if i == 2 else n[1] + 'R'
q.append([dir[i],arr])
visited[dir[i]] = True
t = int(input())
for _ in range(t):
a,b = map(int, sys.stdin.readline().split())
visited = [False for i in range(10000)]
print(bfs(a,b,visited))
python3으로 제출했는데 시간초과가 뜨고 pypy3으로 제출했을때 통과한 코드이다.
이 부분에 대해서는 다음 블로그에서 설명하고 있다.
https://djm03178.tistory.com/16
PyPy3로 제출하면 통과됩니다.
BOJ에서는 Python 3를 위한 제출 언어를 두 가지 제공하고 있습니다. 기본 CPython 인터프리터를 사용하는 Python 3와, 일반적으로 훨씬 빠른 속도를 자랑하는 인터프리터인 PyPy3입니다. 이 글에서 하고
djm03178.tistory.com
'Study > CodingTest' 카테고리의 다른 글
[백준/Python] (S1) 5525 - IOIOI (0) | 2024.04.30 |
---|---|
[백준/Python] (S1) 11286 - 절댓값 힙 (0) | 2024.04.30 |
[백준/Python] (G1) 1107 - 리모컨 (0) | 2024.04.29 |
[백준/Python] (S2) 2630 - 색종이 만들기 (0) | 2024.04.29 |
[백준/Python] (S1) 1389 - 케빈 베이컨의 6단계 법칙 (0) | 2024.04.22 |