백준 1914: 하노이 탑 [Java] - 포포

2022. 5. 8. 18:42알고리즘/코딩테스트(백준)

문제

세 개의 장대가 있고 첫 번째 장대에는 반경이 서로 다른 n개의 원판이 쌓여 있다. 각 원판은 반경이 큰 순서대로 쌓여있다. 이제 수도승들이 다음 규칙에 따라 첫 번째 장대에서 세 번째 장대로 옮기려 한다.

  1. 한 번에 한 개의 원판만을 다른 탑으로 옮길 수 있다.
  2. 쌓아 놓은 원판은 항상 위의 것이 아래의 것보다 작아야 한다.

이 작업을 수행하는데 필요한 이동 순서를 출력하는 프로그램을 작성하라. 단, 이동 횟수는 최소가 되어야 한다.

아래 그림은 원판이 5개인 경우의 예시이다.

입력

첫째 줄에 첫 번째 장대에 쌓인 원판의 개수 N (1 ≤ N ≤ 100)이 주어진다.

출력

첫째 줄에 옮긴 횟수 K를 출력한다.

N이 20 이하인 입력에 대해서는 두 번째 줄부터 수행 과정을 출력한다. 두 번째 줄부터 K개의 줄에 걸쳐 두 정수 A B를 빈칸을 사이에 두고 출력하는데, 이는 A번째 탑의 가장 위에 있는 원판을 B번째 탑의 가장 위로 옮긴다는 뜻이다. N이 20보다 큰 경우에는 과정은 출력할 필요가 없다.

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


public class No1914 {
    static StringBuilder sb;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        sb = new StringBuilder();

        if(n<=20){
            sb.append((int)Math.pow(2, n)- 1).append('\n');
            Hanoi(n, 1 ,2 ,3);
        }else{

            BigInteger b = new BigInteger("1");
            for(int i =0; i<n; i++){
                b = b.multiply(new BigInteger("2"));
            }
            b = b.subtract(new BigInteger("1"));
            sb.append(b).append('\n');
        }
        System.out.println(sb);

    }

    private static void Hanoi(int n, int start, int mid, int to) {
		//이동할 원반의 개수가 1개인 경우
        if(n == 1){
            sb.append(start + " "+ to+'\n');
            return;
        }
		
        //1번 -> 3번으로 원반을 움직일때,  n-1개의 원반을 2번으로 이동
        Hanoi(n-1 , start, to , mid);
		//마지막 1개의 원반을 1 -> 3번으로 이동
        sb.append(start + " " + to + '\n');
        //나머지 2에있는 n-1개의 원반을 3번으로 이동
        Hanoi(n-1, mid, start , to);
    }
}

하노이 탑 이동 규칙은, 작은 원반 위에 더 큰 원반이 올 수 없다는 것이다.
가장 큰(맨 아래에 있는) 원반이 3번으로 이동하기 위해서는, 다른 모든 원반이 2번에 있어야 가능하다.
다음으로, 2번에 있는 n-1개의 원반이 3번으로 이동하면 하노이탑 완성이다.

처음에 n-1개의 원반이 1번에서 2번으로 이동하는 Hanoi(n-1)와, 가장 큰 원반을 3번에 보낸 뒤
2번에 있는 n-1개의 원반을 3번으로 이동하는 Hanoi(n-1)를 적절히 변형해주면 된다.

n이 20보다 큰 경우에는 과정을 생략하고 이동 횟수만 출력하면 된다.
이동횟수는 2^n-1로 문제에서 입력 값으로 ( 1<=n<=100 )가 주어졌다.
long 타입으로 커버할 수 없어 BigInteger 타입을 이용해야 한다.