백준 9019 : DSLR (Java)

CHEDDAR·2025년 8월 13일

알고리즘

목록 보기
24/24
post-thumbnail

백준 9019

문제

네 개의 명령어 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


풀이 아이디어

이 문제는 발생 가능한 모든 명령어 조합이 트리 형태로 구성됨을 떠올리면 쉽게 풀이할 수 있는 문제이다. 최소한의 명령어를 사용해 적절한 명령어 문자열을 찾는 문제이므로 깊이를 기준으로 우선 탐색하는 DFS는 적절하지 않아 BFS 알고리즘을 사용해야 한다. 그러나 일반적인 BFS와 달리 주의해야 할 부분은 방문 처리하는 대상이 명령어 문자열이 아닌 발생한 정수라는 것이다.

아래 예시로 그린 트리를 보면 중복된 명령어 문자열은 발생할 수 없다. 그러나 서로 다른 명령어로 발생시킨 정수는 중복될 수 있다. 아래 트리로 예를 들어보자면 D로 발생시킨 숫자가 1234였는데 SS로 발생시킨 숫자도 1234일 수 있다는 말이다.(임의로 예시를 들은 것이기 때문에 정확히 이 명령어대로 1234가 발생하는 케이스가 존재하지 않을 수 있다.) 이 경우, 명령어를 최대한 덜 사용한 명령어 문자열을 찾아야 하므로 더 빨리 발생한 정수를 미리 방문 처리해 중복 방문되지 않도록 구현해야 한다. 따라서 정수를 방문 처리하는 것이 시간 복잡도를 줄이고 정석적인 BFS를 구현할 수 있는 핵심적인 아이디어이다.

명령어 트리 예시

구현 방법

전형적인 BFS 풀이 방식으로 구현으며 주의 깊게 볼 만한 부분은 방문 처리 배열 구현 정도이다. 발생 가능한 정수 범위가 10^4 미만이기 때문에 복잡하게 구현하지 않고 직관적으로 발생 가능한 정수 크기만큼 선언했다. 그리고 굉장히 모듈화를 시켜두었는데 사실 지금 보니 sepNum은 굳이 분리할 필요 없는 함수인 것 같다. sepNum을 그냥 L 함수와 R 함수에 따로 구현해도 괜찮았을 것 같다.

풀이 코드


import java.io.*; 
import java.util.*; 

public class Main {
	
	public static class Num{
		int val;
		String cmd;
		Num(int val, String cmd){
			this.val = val;
			this.cmd = cmd; 
		}
	}
	
	public static int D(int A) {
		return 2*A%10000;
	}
	
	public static int S(int A) {
		if(A==0) {return 9999;}
		else {return A-1;}
	}
	
	public static int L(int A) {
		int[] d = sepNum(A);
		return d[1]*1000+d[2]*100+d[3]*10+d[0];
	}
	
	public static int R(int A) {
		int[] d = sepNum(A);
		return d[3]*1000+d[0]*100+d[1]*10+d[2];
	}
	
	public static String BFS(int A,int B) {
		
		boolean[] v = new boolean[10000]; 
		v[A] = true; 
		
		Queue<Num> q = new ArrayDeque<>();
		q.offer(new Num(A,""));
		
		while(!q.isEmpty()) {
			Num curr = q.poll();
			if(curr.val == B) {return curr.cmd;}
			
			int dnum = D(curr.val);
			if(!v[dnum]) {v[dnum]= true;q.offer(new Num(dnum,curr.cmd+"D"));}
			
			int snum = S(curr.val);
			if(!v[snum]) {v[snum]= true;q.offer(new Num(snum,curr.cmd+"S"));}
			
			int lnum = L(curr.val);
			if(!v[lnum]) {v[lnum]= true;q.offer(new Num(lnum,curr.cmd+"L"));}
			
			int rnum = R(curr.val);
			if(!v[rnum]) {v[rnum]= true;q.offer(new Num(rnum,curr.cmd+"R"));}

		}
		
		return "";
	}
	
	public static int[] sepNum(int A) {
		
		
		int d1 = A/1000;
		int d2 = (A-d1*1000)/100;
		int d3 = (A-d1*1000-d2*100)/10;
		int d4 = (A-d1*1000-d2*100-d3*10);
		int[] answer = {d1,d2,d3,d4};
		
		return answer;
	}
	
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder(); 
		StringTokenizer st;
		
		int T = Integer.parseInt(br.readLine()); 
		
		for(int i=0;i<T;i++) {
			st = new StringTokenizer(br.readLine()); 
			int A = Integer.parseInt(st.nextToken());
			int B = Integer.parseInt(st.nextToken());
			
			String answer = BFS(A,B); 
			
			sb.append(answer).append("\n");
		}

		br.close();
		System.out.println(sb.toString());
	}

}

profile
SAY CHEESE

0개의 댓글