본문 바로가기

컴퓨터 과학/자료구조 및 알고리즘

백준 11729, 하노이 탑 이동 순서

반응형

문제

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

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

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

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

입력

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

출력

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

 두 번째 줄부터 수행 과정을 출력한다. 두 번째 줄부터 K개의 줄에 걸쳐 두 정수 A B를 빈칸을 사이에 두고 출력하는데, 이는 A번째 탑의 가장 위에 있는 원판을 B번째 탑의 가장 위로 옮긴다는 뜻이다.

예제 입력 1 

3

예제 출력 1 

7
1 3
1 2
3 2
1 3
2 1
2 3
1 3

 찾아보니까 재귀 문제 중에서는 가장 유명한 문제 중 하나인 것 같다. 원판 각각을 생각하면 말도 안되게 복잡한 문제처럼 보이는 데, 재귀를 사용하면 정말 간단하게 해석가능한 문제라고 평가할 수 있겠다.

 해법의 아이디어는 간단하다. 쌓인 원판들을 각각 생각하지 말고, 밑의 가장 큰 원판 하나와 위에 쌓인 나머지 원판의 묶음 하나, 즉 2 개의 원판이 쌓여 있다 가정하는 것이다. 다음 그림과 같이 말이다.

 원판이 2 개만 있는 경우 문제는 간단해진다. 순서는 다음과 같다.

  1.  가장 작은 원판을 버퍼가 되는 축에 끼운다.
  2. 가장 큰 원판을 도착 축에 끼운다.
  3. 버퍼 축에 끼워진 원판을 도착 축에 끼운다.

 코드는 다음과 같다.

#include <iostream>

void hanoi(int N, int start, int end, int buffer) {
	if (N==1) {
		std::cout << start << " " << end <<"\n";
	}
	else {
		hanoi(N - 1, start, buffer, end);
		std::cout << start << " " << end <<"\n";
		hanoi(N - 1, buffer, end, start);
	}
}

int main() {
	int N;
	std::cin >> N;

	std::cout << (1<<N)-1 <<"\n";
	hanoi(N, 1, 3, 2);

	return 0;
}

 묶어서 보는 아이디어를 떠올리는 데 오래걸렸던 문제이다. 마지막에 답은 잘 나오는 데 시간 초과가 떠서 애를 먹기도 했다. 남들이 짠 코드를 보았는데 특별하게 시간을 잡아먹는 부분도 없었는데 말이다. 결과적으로 std::endl을 그냥 "\n"으로 바꾸니까 해결이 되었다. std::endl 대신 "\n"을 사용하는 것 소소한 팁이라면 팁일 수 있겠다. 이 것으로 글을 마친다.

반응형

'컴퓨터 과학 > 자료구조 및 알고리즘' 카테고리의 다른 글

GCD 알고리즘  (1) 2023.11.25
백준 2798, 블랙잭  (0) 2022.11.21
백준 2447, 별 찍기-10  (0) 2022.10.20
백준 10870, 피보나치 5  (1) 2022.10.19
백준 2749, 피보나치 수 3  (2) 2022.09.21