[java]리모컨 - 백준1107
문제
풀이
문제 해석을 하자면,
- 리모컨의 버튼이 0~9 와 +,- 가 존재한다고 가정한다.
- 이때, 고장난 버튼들이 입력으로 주어지면 해당 버튼은 사용못한다.
- 이 상태에서 입력받은 채널 N 으로 이동할때 버튼을 최소 몇 번 눌러야 하는가?
- 단, 수빈이는 현재 채널 100번에 머물러있다.
풀이
-
가장 가까운 수
를 택하는것을 “브루트포스” 로 구하자. -
- “이분탐색”으로 처음에 하려고 했는데 오히려 안풀릴 것 같다.
- 힌트를 보니 그냥 브루트포스! (시간초과가 안나나보네??)
-
가장 가까운 수
를 택할 때 “중복 순열” 로 접근했다. -
전체 흐름
- 사용가능 버튼 찾기
- (1) 채널 100에서 +,- 이동했을 때
- (2) 0~9 숫자입력으로 채널 이동 후 +,- 이동했을 때
- (출력) 둘 중에 더 작은 수를 사용
-
주의 : 예외를 잘 처리해야한다
- 입력값의 길이를 N이라 할 때
가장 가까운 수
의 길이가 N-1, N, N+1 이 될 수 있다는것을 꼭 알고 풀어야한다. - 해당 반례 때문에 한참 시간 낭비ㅜㅜ
- 입력값의 길이를 N이라 할 때
/*
반례 참고 -> N-1, N+1
0
3
0 1 2
output : 4 (N-1 길이의 예)
999
2
9 8
output : 5 (N+1 길이의 예)
*/
코드
static String input;
static int M, uSize;
static int[] breakBtn; // 고장난 버튼
static int[] usedBtn; // 사용가능한 버튼
static int[] outArr;
static int minDiff = Integer.MAX_VALUE;
static int minDiffLen;
public static void main(String[] args) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
input = br.readLine();
M = Integer.parseInt(br.readLine());
breakBtn = new int[M + 1];
if(M!=0) {
StringTokenizer stk = new StringTokenizer(br.readLine(), " ");
for (int i = 0; i < M; i++) {
breakBtn[i] = Integer.parseInt(stk.nextToken());
}
}
//run
//find -> 사용가능 버튼 찾기
findBtn();
//(1) 100에서 +,- 이동했을 때
int result1 = find100();
//(2) 0~9 숫자 이동후 +,- 이동했을 때
int result2 = find0N9();
//output
System.out.println(Math.min(result1, result2));
}
// N-1, N, N+1 일 때를 고려해서 구현했기에 조건문이 다소 복잡하다.
// 범위가 N-1 "이상" 이고 N+1 "이하" 들을 outArr(=`가장 가까운 수`) 로 사용하는것으로 구현했다.
private static void dfs(int depth) {
//base condition
if ((input.length()-1>0 && depth >= input.length()-1) ||
(input.length()-1==0 && depth >= input.length())) {
int findNum = 0;
for (int i = 0; i < depth; i++) {
findNum += + outArr[i]*(int) Math.pow(10,i); // outArr -> 숫자로 변환
}
//debug
// System.out.println(findNum);
int num = Integer.parseInt(input); // 입력값(원본)
int findNumLen = String.valueOf(findNum).length(); // findNum 자리수
minDiff = Math.min(minDiff, Math.abs(num - findNum) + findNumLen);
if (depth == input.length()+1) return; //탈출시점
}
//recursion -> 중복 순열
for (int i=0; i<uSize; i++) {
outArr[depth] = usedBtn[i];
dfs(depth + 1);
}
}
private static int find0N9() {
outArr = new int[7]; // 최대 1,000,000 까지 가까운 수 택 가능하므로 7자리로 설정
dfs(0);
int diff = minDiff;
return diff;
}
private static int find100() {
int inNum = Integer.parseInt(input);
int diff = Math.abs(inNum - 100);
return diff;
}
static void findBtn() {
usedBtn = new int[10];
boolean[] vis = new boolean[10]; // 방문배열로 고장난 버튼 판별
for (int i = 0; i < M; i++) {
vis[breakBtn[i]] = true;
}
int idx=0;
for (int i = 0; i <= 9; i++) {
if(vis[i]) continue;
usedBtn[idx++] = i;
}
uSize = idx;
}
느낀점
1년 전에 제출기록이 있어서 확인해보니 이 코드보다 훨씬 짧게 구현했던 기록이 있다.
아마 그때는 구글링을 해서 다른사람의 코드를 참고했었던것 같다.
지금 코드는 너무 난해하지만 스스로 풀었다는것에 만족..!
댓글남기기