베오
DCode
베오
전체 방문자
오늘
어제
  • 분류 전체보기 (218)
    • 공지사항 (1)
    • 잡설 (1)
    • Programming (33)
      • [C] (1)
      • [Java] (4)
      • [Python] (2)
      • [Android] (2)
      • [Network] (0)
      • [Operation System] (2)
      • [Spring Boot] (22)
      • [Docker] (0)
    • Algorithm (31)
      • 자료구조 (2)
      • 알고리즘 (Java) (14)
      • 알고리즘 (기초) (15)
    • Coding Test (131)
      • BOJ (131)
      • Algospat (0)
    • 이론적인거 (14)
      • 보안 (5)
      • 오류 해결 (2)
      • 디자인 패턴 (5)
      • 네트워크 (1)
      • 기타 (1)
    • 최신기술 (4)
      • 블록체인 (1)
    • [Project] (1)

블로그 메뉴

  • 🐈‍⬛ GitHub
  • 📫 방명록
  • 🔖 태그

공지사항

인기 글

티스토리

hELLO · Designed By 정상우.
베오

DCode

Coding Test/BOJ

[BOJ/JAVA] 1107번: 리모컨

2022. 8. 21. 10:29

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.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class java_1107 {
    static String target;
    static int N;
    static boolean brokenButton[];

    // N보다 큰, 작은 수 바로 근처
    static int targetMin = -987654321;
    static int targetMax = 987654321;

    static boolean isZeroPossible;

    static int minNotBroken = 10;
    static int maxNotBroken = -1;

    // targetMax> number && N < number
    public static void checkNumber(int number, int position) {
        if (position == target.length()) {
            if (N - targetMin > N - number && number < N) {
                targetMin = number;
            }
            if (targetMax - N > number - N && number > N) {
                targetMax = number;
            }
            return;
        }

        // 현재 자리의 숫자
        int digit = target.charAt(position) - '0';
        // 현재 자리
        int numberPosition = (int) Math.pow(10, target.length() - position - 1);

        // 현재 숫자를 쓴다면,
        if (!brokenButton[digit]) {
            checkNumber(number + digit * numberPosition, position + 1);
        }

        // 현재 숫자를 쓰지 않는다면

        // 현재 숫자보다 살짝 큰 숫자 찾기
        // 현재 숫자보다 살짝 작은 숫자 찾기

        int brokenLarge = -1;
        int brokenLess = 10;

        for (int j = digit + 1; j < brokenButton.length; j++) {
            if (!brokenButton[j]) {
                brokenLarge = j;
                break;
            }
        }

        for (int j = digit - 1; j >= 0; j--) {
            if (!brokenButton[j]) {
                brokenLess = j;
                break;
            }
        }

        // 큰 숫자가 없다면 처리하지 않음
        if (brokenLarge != -1) {
            int tmpIndex = position + 1;
            int tmpNumber = number + brokenLarge * numberPosition;

            // 나머지 가장 작은걸로 채우기
            while (tmpIndex < target.length()) {
                // 현재 자리
                int tmpNumberPosition = (int) Math.pow(10, target.length() - tmpIndex - 1);

                if (!isZeroPossible) {
                    tmpNumber += minNotBroken * tmpNumberPosition;
                }
                tmpIndex++;
            }

            checkNumber(tmpNumber, target.length());

        }
        // 작은 숫자가 없다면 처리하지 않음
        if (brokenLess != 10) {
            int tmpIndex = position + 1;
            int tmpNumber = number + brokenLess * numberPosition;

            // 나머지 가장 작은걸로 채우기
            while (tmpIndex < target.length()) {
                // 현재 자리
                int tmpNumberPosition = (int) Math.pow(10, target.length() - tmpIndex - 1);

                tmpNumber += maxNotBroken * tmpNumberPosition;

                tmpIndex++;
            }
            // 나머지 자릿수를 가장 큰 것으로 채움
            checkNumber(tmpNumber, target.length());
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        // 최대한 N에 있는 숫자를 누를 것
        // N에 있는 숫자가 없으면
        // 올리는게 이득인지
        // 내리는게 이득인지 판별할 것

        target = br.readLine();
        N = Integer.parseInt(target);

        // 고장난 버튼의 갯수
        int c = Integer.parseInt(br.readLine());

        brokenButton = new boolean[10];

        if (c > 0) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            for (int i = 0; i < c; i++) {
                brokenButton[Integer.parseInt(st.nextToken())] = true;
            }
        }

        // 정상적인 숫자중 가장 큰 것과 가장 작은 것
        minNotBroken = 10;
        maxNotBroken = -1;

        isZeroPossible = !brokenButton[0];

        for (int i = 1; i < 10; i++) {

            if (!brokenButton[i]) {
                if (minNotBroken > i) {
                    minNotBroken = i;
                }
                if (maxNotBroken < i) {
                    maxNotBroken = i;
                }
            }
        }

        int count = Integer.MAX_VALUE;

        // 1. 숫자만 눌러서 만들 수 있는 경우
        // 숫자를 돌면서 망가진 버튼이 없어야 함
        for (int i = 0; i < target.length(); i++) {
            if (brokenButton[target.charAt(i) - '0']) {
                break;
            }

            if (i == target.length() - 1) {
                count = Math.min(count, target.length());
            }
        }

        // 2. +, - 만 눌러서 만들 수 있는 경우
        // 100번에서 +, - 로 이동하는 경우
        count = Math.min(count, Math.abs(100 - N));

        // 3-1. 증가한 자릿수에서 빼기
        int tmpNumber = minNotBroken * (int) Math.pow(10, target.length());
        for (int i = 0; i < target.length(); i++) {
            if (!isZeroPossible) {
                tmpNumber += minNotBroken * (int) Math.pow(10, target.length() - 1 - i);
            }
        }

        count = Math.min(count, Math.abs(N - tmpNumber) + target.length() + 1);

        // 3-2. 감소한 자릿수에서 더하기
        if (target.length() >= 2) {
            tmpNumber = maxNotBroken * (int) Math.pow(10, target.length() - 2);
            for (int i = 2; i < target.length(); i++) {

                tmpNumber += maxNotBroken * (int) Math.pow(10, target.length() - 1 - i);

            }
            count = Math.min(count, Math.abs(N - tmpNumber) + target.length() - 1);
        }

        checkNumber(0, 0);
        // System.out.println(targetMin + " " + targetMax);

        if (targetMax - N >= 0) {
            count = Math.min(count, targetMax - N + target.length());
        }
        if (N - targetMin >= 0) {
            count = Math.min(count, N - targetMin + target.length());
        }

        // 0을 누르고 이동하는 경우
        if (isZeroPossible) {
            count = Math.min(N + 1, count);
        }

        bw.write(count + "\n");

        br.close();
        bw.close();
    }
}
저작자표시 (새창열림)

'Coding Test > BOJ' 카테고리의 다른 글

[BOJ/JAVA] 9205번: 맥주 마시면서 걸어가기  (0) 2022.08.21
[BOJ/JAVA] 1937번: 욕심쟁이 판다  (0) 2022.08.21
[BOJ/JAVA] 4920 테트리스 게임  (0) 2022.08.21
[BOJ/JAVA] 3085번: 사탕 게임  (0) 2022.08.21
[BOJ/JAVA] 4195번: 친구 네트워크  (0) 2022.08.21
    'Coding Test/BOJ' 카테고리의 다른 글
    • [BOJ/JAVA] 9205번: 맥주 마시면서 걸어가기
    • [BOJ/JAVA] 1937번: 욕심쟁이 판다
    • [BOJ/JAVA] 4920 테트리스 게임
    • [BOJ/JAVA] 3085번: 사탕 게임
    베오
    베오

    티스토리툴바