안녕하세요 coding-knowjam입니다.
오늘은 백준 온라인 저지에 있는 1107번 리모컨 문제를 풀어보겠습니다.
문제에 대한 링크는 아래에 있으니 문제를 먼저 읽고 와주시길 바랍니다.
https://www.acmicpc.net/problem/1107
1. 문제 설명
해당 문제는 모든 경우의 수를 확인해서 풀어야 하는 완전 탐색, 브루트 포스 유형의 문제입니다.
실제로 문제를 풀다 보면 경우의 수를 하나씩 놓치게 되는데 생각보다 고려해야 할 사항이 많습니다.
특별한 알고리즘보다는 경우의 수만 잘 확인하면 풀리는 문제이므로 막상 풀면 어렵지 않았다고 생각하실 겁니다.
먼저 문제에서 요구하는 사항은 현재 채널은 100번이며 이동해야 할 채널까지 리모컨 버튼을 얼마나 최소로 클릭할 수 있느냐입니다.
문제를 풀기 위해 고려해야 할 경우의 수는 다음과 같습니다.
- 현재 채널(100)과 타깃 채널(이동해야 할 채널)이 같은 경우
- 타깃 채널로 리모컨 숫자 버튼만 눌러서 이동한 경우
- 현재 채널에서 타깃 채널까지 +,- 버튼만 눌러서 이동한 경우
- 리모컨 숫자 버튼을 눌러서 타깃 채널에 가장 근접한 작은 채널로 이동한 후 + 버튼을 눌러서 이동한 경우
- 리모컨 숫자 버튼을 눌러서 타깃 채널에 가장 근접한 큰 채널로 이동한 후 - 버튼을 눌러서 이동한 경우
위의 5가지 경우를 고려하면 되는데 각각의 경우에서 구해지는 버튼 누름 횟수 중 가장 최솟값을 출력하면 됩니다.
추가로 4번의 경우 채널이 무한대만큼 존재하므로 적절한 기준으로 탐색을 중지할 수 있도록 신경 써야 합니다.
그럼 코드를 살펴보겠습니다.
2. Java로 문제 풀이
package study.blog.codingknowjam.algorithm.boj;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
import java.util.Scanner;
import java.util.stream.IntStream;
public class BOJ_1107 {
private static final Scanner scanner = new Scanner(System.in);
// 리모컨 숫자버튼 누른 횟수
private static int numberPadClickCount = 0;
private static int currentMinValue = Integer.MIN_VALUE;
//백준온라인저지 1107번 리모컨 문제풀이
public static void main(String[] args) {
// 리모컨
RemoteController remoteController = RemoteController.create();
// 현재 채널
Channel currentChannel = Channel.of(100);
// 이동해야 할 채널
Channel targetChannel = Channel.of(scanner.nextInt());
// 리모컨 버튼 망가짐
breakButton(remoteController, scanner);
// 현재 채널과 타켓 채널이 동일한 경우 -> 버튼 안눌러도 되므로 0이 최소값
if (targetChannel.equals(currentChannel)) {
System.out.println(numberPadClickCount);
return;
}
// 리모컨 숫자버튼 눌러서 타켓 채널로 이동 가능한 경우 -> 숫자버튼 누른 횟수가 최소값
int count1 = Integer.MAX_VALUE;
if (remoteController.isPress(targetChannel.value())) {
count1 = numberPadClickCount;
}
// 리모컨 +, - 버튼만 눌러서 채널 이동한 경우 -> +, - 버튼 누른 횟수가 최소값
int count2 = currentChannel.getDifferenceValue(targetChannel);
// 현재 리모컨으로 이동할 수 있는 채널 중 타켓채널에 가장 근접한 작은 채널로 이동한 경우
// -> 숫자버튼 누른 횟수 + "+, -" 버튼 누른 횟수가 최소 값
int count3 = currentChannel.moveLessTargetChannel(targetChannel, remoteController);
// 현재까지 중 최소값 구하기
currentMinValue = getMinValue(count1, count2, count3);
// 현재 리모컨으로 이동할 수 있는 채널 중 타켓채널에 가장 근접한 큰 채널로 이동한 경우
// -> -> 숫자버튼 누른 횟수 + "+, -" 버튼 누른 횟수가 최소 값
// ## 채널이 무한대이므로 currentMinValue 값보다 버튼 누른 횟수 많으면 종료
int count4 = currentChannel.moveGreaterTargetChannel(targetChannel, remoteController);
// 최종 최소값 비교해서 결과 출력
System.out.println(Math.min(currentMinValue, count4));
}
private static int getMinValue(int value1, int value2, int value3){
return Math.min(value1, Math.min(value2, value3));
}
private static void breakButton(RemoteController remoteController, Scanner scanner) {
IntStream.range(0, scanner.nextInt())
.forEach(ignore -> remoteController.breakButton(scanner.nextInt()));
}
static class RemoteController {
private final HashMap<Integer, Integer> numberPad = new HashMap<>();
private RemoteController() {
IntStream.range(0, 10)
.forEach(number -> numberPad.put(number, 1));
}
public static RemoteController create() {
return new RemoteController();
}
public void breakButton(int buttonNumber) {
numberPad.put(buttonNumber, 0);
}
public boolean isPress(int channel) {
String[] digitsArray = String.valueOf(channel).split("");
numberPadClickCount = digitsArray.length;
long matchCount = Arrays.stream(digitsArray)
.map(Integer::parseInt)
.filter(integer -> numberPad.get(integer) == 1)
.count();
return matchCount == digitsArray.length;
}
}
static class Channel {
private int channel;
private Channel(final int channel) {
this.channel = channel;
}
public static Channel of(final int channel) {
return new Channel(channel);
}
private int moveLessTargetChannel(Channel targetChannel, RemoteController remoteController) {
boolean end = false;
channel = targetChannel.value();
while (!end) {
if (channel <= 0) {
numberPadClickCount = 99999999;
break;
}
channel--;
end = remoteController.isPress(channel);
}
return targetChannel.value() - channel + numberPadClickCount;
}
private int moveGreaterTargetChannel(Channel targetChannel, RemoteController remoteController) {
boolean end = false;
channel = targetChannel.value();
while (!end) {
if (channel >= targetChannel.value() + currentMinValue) {
numberPadClickCount = 99999999;
break;
}
channel++;
end = remoteController.isPress(channel);
}
return channel - targetChannel.value() + numberPadClickCount;
}
public int getDifferenceValue(Channel closeChannel) {
return Math.abs(this.channel - closeChannel.channel);
}
public int value() {
return this.channel;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Channel channel1 = (Channel)o;
return channel == channel1.channel;
}
@Override
public int hashCode() {
return Objects.hash(channel);
}
}
}
알고리즘 문제를 풀면서 너무 절차 지향적으로 작성하는 것 같아 최대한 객체지향스럽게 작성해보았습니다.
모든 코드에 주석을 달지는 않았지만 특별한 알고리즘이 존재하지 않으므로 이해하는데 크게 어렵지 않으실 겁니다.
감사합니다.
'Algorithm & Data Structure > 문제풀이' 카테고리의 다른 글
[Algorithm] 백준 5639번(BOJ 5639) 이진검색트리 문제풀이! (Java) (0) | 2022.04.04 |
---|---|
[Algorithm] 백준 1655번(BOJ 1655) 가운데를 말해요 (Java) (0) | 2022.04.04 |
[Algorithm] 백준 17142(BOJ 17142) 연구소 3 문제풀이! (Java) (0) | 2021.11.14 |
[Algorithm] 백준 14500(BOJ 14500) 테트로미노 문제풀이!! (Java) (0) | 2021.10.28 |
[Algorithm] 백준 4095번(BOJ 4095) 최대 정사각형 문제풀이!!(Java) (0) | 2021.10.19 |
댓글