https://www.acmicpc.net/problem/1107
문제 설명
수빈이는 TV를 보고 있다. 수빈이는 채널을 돌리려고 했지만, 버튼을 너무 세게 누르는 바람에, 일부 숫자 버튼이 고장났다.
리모컨에는 버튼이 0부터 9까지 숫자, +와 -가 있다. +를 누르면 현재 보고있는 채널에서 +1된 채널로 이동하고, -를 누르면 -1된 채널로 이동한다. 채널 0에서 -를 누른 경우에는 채널이 변하지 않고, 채널은 무한대 만큼 있다.
수빈이가 지금 이동하려고 하는 채널은 N이다. 어떤 버튼이 고장났는지 주어졌을 때, 채널 N으로 이동하기 위해서 버튼을 최소 몇 번 눌러야하는지 구하는 프로그램을 작성하시오.
수빈이가 지금 보고 있는 채널은 100번이다.
입력
첫째 줄에 수빈이가 이동하려고 하는 채널 N (0 ≤ N ≤ 500,000)이 주어진다. 둘째 줄에는 고장난 버튼의 개수 M (0 ≤ M ≤ 10)이 주어진다. 고장난 버튼이 있는 경우에는 셋째 줄에는 고장난 버튼이 주어지며, 같은 버튼이 여러 번 주어지는 경우는 없다.
출력
첫째 줄에 채널 N으로 이동하기 위해 버튼을 최소 몇 번 눌러야 하는지를 출력한다.
문제 접근
최소 횟수는 가장 근접한 채널의 번호를 누르고 거기서부터 +나 - 버튼을 눌러 이동하는 방식이다. '가장 근접한' 채널을 찾기 위해, 채널을 하나하나 탐색하여 최솟값을 비교한다.
문제 풀이
데이터를 입력 받을 때 고장난 버튼을 따로 저장한다. button이라는 배열은 크기가 10이고, 각 인덱스는 버튼의 번호를 나타낸다. 고장난 경우 1, 고장나지 않은 경우 0이 저장됨.
우선 min 값의 초깃값은 N - 100으로 잡는다. 현재 있는 채널이 100번으로 고정되어 있으며 여기서 +나 - 버튼만 눌러 목적 채널까지 이동하는 것이 현재 찾을 수 있는 가능한 최솟값이기 때문이다.
이후 반복문을 돌며 채널을 하나하나 검사하고 비교해주면 된다.
이때 for문의 범위를 0~999900으로 지정해준 이유는 우선 첫째, 번호 버튼으로 만들 수 있는 가장 작은 값이 0이다. 둘째, 찾을 채널의 최댓값이 500,000이며 이때 가능한 최솟값 중 최댓값은 499,900이 된다. 그러면 버튼이 어떻게 고장나든간에 (999,900 - 500,000) 보다 큰 값은 확인할 필요가 없다.
그리고 버튼을 누른 횟수를 세어야 하므로 채널을 옮기기 위해 누른 숫자 버튼도 생각해주어야 한다.
vaild 함수는 단순히 현재 채널에 못 누르는 숫자가 있는지 판단해주는데, 아까 input 함수에서 M이 0이 아닌 경우에만 배열을 실질적으로 만들어 값을 넣게 해뒀으므로 M이 0인 경우엔 이 함수에 접근하지 못하도록 처리해주었다. (if문에서 M == 0 || isValid(ch) 부분. 앞쪽 조건이 참인 경우 뒷쪽 조건은 검사하지 않고 넘어가기 때문에 가능한 코드)
전체 코드
package bruteForce;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
/*
* BOJ 1107 - 리모컨
*/
public class BOJ1107 {
static int N, M; // N -> 옮길 채널
static int[] button;
public static void main(String[] args) throws IOException {
input();
int min = Math.abs(N - 100); // 초기 채널에서 +-만 눌러서 만들어지는 값
for(int i = 0; i<999901; i++) { // 500,000 - 100 = 499,900을 500,000에 대충 더한값
String ch = String.valueOf(i);
if(M == 0 || isValid(ch)) { // 가능한 값인 경우, M이 0이면 valid는 수행X
int count = Math.abs(N - i) + ch.length(); // 채널버튼 + (+-)버튼
if(count < min) min = count;
}
}
System.out.println(min);
}
static void input() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
M = Integer.parseInt(br.readLine());
if (M != 0) {
StringTokenizer st = new StringTokenizer(br.readLine());
button = new int[10]; // 0~9 각 버튼을 나타냄
for(int i=0; i<M; i++) { // 고장난 버튼 표시
button[Integer.parseInt(st.nextToken())] = 1;
}
}
}
static boolean isValid(String ch) {
for(int i = 0; i < ch.length(); i++) {
if(button[ch.charAt(i) - '0'] == 1)
return false;
}
return true;
}
}
결과 및 평가
사실 1년전쯤에 풀었던 문제였는데, 완전탐색 알고리즘 복습하면서 다시 풀어봤다. 아무 생각없이 풀었더니 이전보다 메모리랑 시간이 더 안 좋아졌길래 수정을 좀 해서 다시 제출했다.
이전과 바뀐 부분은 채널 범위랑 입출력(Scanner에서 BufferedReader로 변경), 스트링 값으로 버튼 인덱스 지정해주는 부분 정도? 획기적으로 뭔갈 바꾸어냈다! 하는 부분은 없었다.
'문제풀이' 카테고리의 다른 글
[백준 14499] 주사위 굴리기 - JAVA (0) | 2022.02.09 |
---|---|
[백준 10815] 숫자 카드 - JAVA (0) | 2022.01.07 |
[백준 1946] 신입 사원 - JAVA (0) | 2022.01.06 |
[백준 1697] 숨바꼭질 - JAVA (0) | 2022.01.05 |
Comment