Java - 알고리즘

백준 16953 - A - > B

TerianP 2022. 8. 9.
728x90

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

 

16953번: A → B

첫째 줄에 A, B (1 ≤ A < B ≤ 109)가 주어진다.

www.acmicpc.net

문제

정수 A를 B로 바꾸려고 한다. 가능한 연산은 다음과 같은 두 가지이다.

  • 2를 곱한다.
  • 1을 수의 가장 오른쪽에 추가한다. 

A를 B로 바꾸는데 필요한 연산의 최솟값을 구해보자.

 

입력

첫째 줄에 A, B (1 ≤ A < B ≤ 109)가 주어진다.

 

출력

A를 B로 바꾸는데 필요한 연산의 최솟값에 1을 더한 값을 출력한다. 만들 수 없는 경우에는 -1을 출력한다.

 

예제 

2 162

예제 출력

5

풀이방법

이 문제는 문제 풀이 방법은 쉽게 떠오르지만, 코드를 짜기는 어려운...그런 문제 중 하나였다.

특히 다른 부분보다 값을 만들 수 없는 경우에 -1 을 출력한다. 라는 부분을 어떻게 코드로 구현할까에 대해서 많이 고민했던 것 같다.

 

이 문제는 크게 3가지로 생각한다.

 

1. A -> B 연산하기 => 숫자 A 에 2를 곱하는 경우와 숫자 A 의 가장 오른쪽에 1을 추가하는 경우

- 2를 곱하는 경우는 사실 아주 쉽고, 오른쪽에 1을 추가하는 경우가 살짝 고민을 해야하는 편에 속한다. 나는 오른쪽에 1을 추가하는 부분을 현재 값 *10 +1 연산을 하는 것으로 대체하였다. 결국 오른쪽에 1을 추가한다는 것은 현재 값이 얼마이던 상관없이 현재 값의 일의 자리가 1 이 된다는 것이고 이에 따라서 현재값*10+1 을 한다.

 

 

2. 연산 도중 A 가 B 를 넘거나 A 가 B 와 같아지는 경우

연산 중 A 가 B 를 초과하는 경우는 뭘 해도 결국 B 에 도달 할 수 없음으로 현재의 result 값을 return 한다. 만약 A와 B 가 동일한 경우 cnt 가 얼마인지 계산하고, 해당 값과 현재 result 의 값을 비교해서 더 작은 숫자를 result 에 담는다.

 

3. A 가 B 에 도달 할 수 없는 경우

A 가 B 에 도달 할 수 있는지 여부를 판단하기 위해서 flag 를 쓰는 방법과 나처럼 result 값이 변화가 있는지 확인하는 방법 2가지로 나눌 수 있을 것 같다.

나는 result 를 Integer.MIN_VALUE 로 지정해두고(integer 타입의 최솟값) 이 값이 변화가 있는지 확인하였다. 만약 findNumber 이 돌면서 값이 계산되었을 때 결국 result 의 값이 변화가 없다면 단 한번도 A 가 B 에 도달하지 못한 것이고 따라서 result 값은 그대로 일 것이다. 이러한 경우 -1 이 출력되도록 하였다.

package baekJoon;

import java.io.*;
import java.util.StringTokenizer;

public class Quiz_16953_풀이완료 {
    static long a, b; // int 타입으로 설정하면 틀림!! => 문제가 int 가 아닌 long 으로 받기 때문인듯?
    static int result = Integer.MAX_VALUE; // 결과값 -> 처음은 최대값

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

        StringTokenizer st = new StringTokenizer(br.readLine()); // 입력

        a = Integer.parseInt(st.nextToken());
        b = Integer.parseInt(st.nextToken());

        // 만약 아래 dfs 메서드가 돌고 끝난 후 result 를 출력하는데
        // 이때 result 가 변화가 없이 처음과 동일한 Integer.Max_val 이라면 -1 출력
        // 아니라면 현재 result+1 출력
        if( findNumber(a, 0) == Integer.MAX_VALUE){
            bw.append("-1");
        }else{
            bw.write((result+1)+"\n");
        }
        bw.flush();
        bw.close();
    }

    // sum 을 기준으로 dfs 가 돌기 시작
    // 만약 sum 이 b 보다 커지면 그냥 result 를 return => b 보다 커졌다라는건 b 에 도달할 수 없다는 의미임으로 그냥 패스하기위해
    // 변화가 없는 result 를 그대로 출력
    // 만약 sum 이 b 와 동일하다면 즉 a 가 b 가 될 수 있다면 a 가 b 로 바뀔때마다 cnt 값을 계산한 후
    // result 와 cnt 값을 비교해서 더 작은 최소값을 result 에 담음

    // else 구문은 sum 에서 2 를 곱하거나
    // sum 에서 10 을 곱하고 1을 더하는 연산을 함
    // ==> 맨 뒤에 1을 추가한다는 건 결국 현재 있는 값이 10의 자리의 수가 된다는 것이고,
    // 그 후 1의 자리에 1이 들어간다는 의미임으로 sum*10+1
    static int findNumber(long sum, int cnt){
        if (sum > b) {
            return result;
        }
        if (sum == b) {
            result = Math.min(result, cnt);
//            System.out.println("result : " + result);

        } else{
            findNumber(sum * 2, cnt+1);
            findNumber(sum * 10 + 1, cnt + 1);
        }

        return result;
    }
}

 

'Java - 알고리즘' 카테고리의 다른 글

백준 - 12851 숨바꼭질2  (0) 2022.08.13
백준 1679 - 숨바꼭질 BFS  (0) 2022.08.09
백준 1303 : 전투 DFS BFS 풀이  (0) 2022.07.17
백준 : 2468 안전 영역  (0) 2022.07.14
백준 : 4963 섬의 개수  (0) 2022.07.10

댓글