PS/etc

백준 1107번: 리모컨 (Java)

닻과매 2022. 6. 17. 10:37

https://www.acmicpc.net/problem/1107

 

1107번: 리모컨

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

www.acmicpc.net

문제

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

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

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

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

입력

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

출력

첫째 줄에 채널 N으로 이동하기 위해 버튼을 최소 몇 번 눌러야 하는지를 출력한다.

 


 

초기 풀이

처음에 BFS로, while문 안에서 queue의 원소 꺼내고, queue의 원소에 0~9 중 안 고장난 버튼 숫자 붙이거나 +1, -1하는 방식으로 풀려고 했다. 하지만 현재 채널에 도착했으면 거기에서 숫자를 붙일 수 없다(리모컨을 다들 써봐서 잘 알 것이다.). 따라서, 숫자를 붙여서 만들 수 있는 모든 숫자를 만들고, 거기에서 목적지까지의 거리를 구해야 한다. 다만, BFS로 가능한 숫자를 생성하면 '입력하여 도착한 100'을 구분하지 못하는 경우가 생길 수 있어, 구현에서 고려해주어야 한다.

 

풀이

브루트포스 방식으로 6자리 이하의 가능한 모든 숫자를 만든다. 이후, '|목적지-현재 숫자|+현재 숫자의 길이'가 가장 작은 값을 찾으면 된다. 또한, 100이 시작 채널이기에 '|목적지-100|'도 정답의 후보군이다.

 

유의할 점

1. 100에서도 시작하기에 찾아야 한다.

2. 찾는 채널은 50만 이하이지만, 50만 초과의 채널로 갈 수 있다.

3. 0도 가능한 채널이다.

4. 6자리 이하만 찾으면 되는 이유: 100에서 500000까지 +버튼을 누르면 499900번이 걸리는데, 100만 이상에서 500000까지는 최소 500007번이 걸리기 때문이다. 만약 문제의 N 범위가 0이상 700000 이하이고 가능한 숫자 버튼이 1뿐이라면, 1111111로 간 후 내려가는게 111111에서 올라가는거보다 빠를 것이다.

5. 이 외에도 많은 실수할만한 요소들이 있다: 열심히 풀고, 나름대로 디버깅도 했는데 '맞왜틀?'에 빠졌다면, 반례1, 반례2를 통해 잘 찾아보자.

 

배운 점

브루트포스 풀이의 코드를 보면 그렇게 어렵지 않다. 풀이 방법을 잘 파악할 필요가 있다.

SWEA 4311과 유사한 듯?

 

코드

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
import java.io.*;
import java.util.*;
 
public class Main {
    
    static int ans = 1000000;
    static boolean[] nums;
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());
        int M = Integer.parseInt(br.readLine());
        nums = new boolean[10];
        Arrays.fill(nums, true);
        StringTokenizer st = null ;
        if (M > 0) st = new StringTokenizer(br.readLine());
        for (int i = 0; i < M; i++) {
            nums[Integer.parseInt(st.nextToken())] = false;
        }
        
        ans = Math.abs(N-100);
        for (int i = 0; i <= 9; i++) {
            if (!nums[i]) continue;
            dfs(i, N, 1);
        }
        System.out.println(ans);
    }
    
    static void dfs(int cur, int N, int len) {
        if (len >= 7return;
        ans = Math.min(ans, Math.abs(N-cur) + len);
        for (int i = 0; i <= 9; i++) {
            if (!nums[i]) continue;
            dfs(10*cur+i, N, len+1);
        }
    }
}
 
cs