알고리즘

백준 1107 리모컨

오래먹는오레오 2021. 5. 19. 16:58

리모컨 : https://www.acmicpc.net/problem/1107

 

1107번: 리모컨

첫째 줄에 수빈이가 이동하려고 하는 채널 N (0 ≤ N ≤ 500,000)이 주어진다.  둘째 줄에는 고장난 버튼의 개수 M (0 ≤ M ≤ 10)이 주어진다. 고장난 버튼이 있는 경우에는 셋째 줄에는 고장난 버튼

www.acmicpc.net

리모컨 일부 숫자가 고장났다 이때 멀쩡한 버튼과 +,-버튼만가지고 원하는 채널까지 갈때 최소 몇번 눌러야 하는지 구하는 문제 였다.

완탐을 통해 입력할수 있는 모든 숫자를 가지고 비교를 하였다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

public class 리모컨 {
	public static String targetChannel;
	public static int N = 0, answer = Integer.MAX_VALUE;
	public static List<Integer> button = new ArrayList<Integer>();

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		targetChannel = br.readLine();
		N = Integer.parseInt(br.readLine());
		if (N != 0) {
			st = new StringTokenizer(br.readLine());
		}
		for (int n = 0; n < N; n++) {
			button.add(Integer.parseInt(st.nextToken()));
		}
		dfs(0, new StringBuilder());
		answer = answer > Math.abs(Integer.parseInt(targetChannel) - 100)
				? Math.abs(Integer.parseInt(targetChannel) - 100)
				: answer;
		System.out.println(answer);
	}

	public static void dfs(int count, StringBuilder sb) {
		if (count > targetChannel.length()) {
			return;
		}

		for (int i = 0; i < 10; i++) {
			if (button.contains(i)) {
				continue;
			}
			sb.append(i);
			int result = sb.length() + Math.abs(Integer.parseInt(targetChannel) - Integer.parseInt(sb.toString()));
			answer = answer > result ? result : answer;
			dfs(count + 1, sb);
			sb.deleteCharAt(sb.length() - 1);
		}
	}
}

dfs의 종료 조건은 targetChannel보다 size가 클경우로 해주었다.

그 이유는

997

8

2 3 4 5 6 7 8 9

와 같은 케이스 였기 때문이다. 이경우 1000에서 3번 - 한것이 제일 빠르기 때문이다.

만약 count == targetChannel이라고 했다면 111에서 997까지 +로 올라가야 하기 때문에 비효율 적이다.

또한

answer = answer > Math.abs(Integer.parseInt(targetChannel) - 100)
				? Math.abs(Integer.parseInt(targetChannel) - 100)
				: answer;

해당 조건을 넣어주어 +,-로 이동이 더 빠른 경우를 해결해 주었다.

마지막으로 고장난 버튼이 없는경우도 있기때문에 StringTokenizer를 고장난 버튼이 있는경우에만 생성해주어야한다

그렇지 않으면 85%쯤에서 런타임애러(NullPointer)를 겪게 된다 ㅠㅠ

if (N != 0) {
			st = new StringTokenizer(br.readLine());
}

이번 문제는 다양한 조건을 생각 해야 했기 때문에 굉장히 좋은 문제 였던것 같다.