Algorithm

[Algorithm] 하노이의 탑 알고리즘 (재귀)

보라해바라기 2023. 8. 12. 23:20
SMALL

💜 하노이의 탑이란?

1) 정의

- 하노이의 탑은 퍼즐의 일종으로, 세 개의 기둥과 이 기둥에 꽂을 수 있는 크기가 다양한 원판들이 있고, 퍼즐을 시작하기 전에는 한 기둥에 원판들이 작은 것이 위에 있도록 순서대로 쌓여 있다.

 

2) 조건

  1. 한 번에 한개의 원판만 옮길 수 있다.
  2. 가장 위에 있는 원판만 이동할 수 있다.
  3. 큰 원판이 작은 원판 위에 있어서는 안 된다

3) 목표

- 세 막대를 왼쪽부터 A, B, C라고 가정하자.

- 위 조건에 맞게 모든 원판을 A에서 C로 옮겨야 한다.

 


💜 어떤 기능을 하는 함수를 구현해야하는가? (문제 정의)

- 원반의 이동 횟수를 최소화한다.

- 각 원반을 옮기는 모든 순서를 출력한다.

=> 원반 개수 N개를 입력 받아, 모든 원반을 C막대에 옮기는 모든 과정을 출력한다.

 


💜 문제를 어떻게 해결할 것인가? (아이디어 얻기)

- 원반의 개수에 따라 알고리즘이 더 복잡해진다.

- 원반의 개수가 최소인 경우를 실제로 해보자! > 원반 3개를 가지고 해보자!

1) 분할정복(Divide and conquer): 큰 문제를 작은 문제로 세분화하여 해결

원반이 3개일 때

 

 2) 재귀를 활용!

: N-1개의 원판 > 맨 밑에 있는 원판 1개 + 위에 있는 나머지 N-2개의 원판

: 위의 원판이 1이 될 때까지 똑같은 프로세스 반복 > 재귀 필요!


💜 문제 접근하기 (원반 N개로 가정)

- 원반이 n개 있다고 가정한다.

- 원반을 옮길 때는 반드시 막대 3개를 다 거쳐야 한다. (원반이 1개일 때는 해당 X)

 

[원상태]

: 맨 밑의 원반 1개, 그 위의 원반 n-1개를 한 묶음으로 본다.

 

[1단계]

: N-1개의 원판을 A > B 로 옮긴다. (실제 코드 구현 시, A > C > B 순)

[2단계]

: 맨 밑의 원판 1개를 A > C로 옮긴다.

[3단계]

: N-1개의 원판을 B > C 로 옮긴다. (실제 코드 구현 시, B > A > C 순)


💜 실제 코드 & 분석

// 하노이의 탑
// n개의 원판을 by(중간)을 거쳐서 from(처음)에서 to(목표)로 이동
void tower_of_hanoi(int n, char from, char by, char to) {
	// 종료 조건: 옮겨야 하는 원판의 수가 1개일 때! > 그냥 옮기면 됨.
	if (n == 1) {
		printf("원판 1개를 %2c -> %2c로 이동하였습니다.\n", from, to);
	}
	else {
		// 원판 n-1개를 (맨 아래 제외) a -> b로 이동 => 중간 이동!
		// [1단계]              
		tower_of_hanoi(n - 1, from, to, by); // from > to > by (from에서 to를 거쳐서 중간인 by로 이동)

		// 큰 원판 1개 (맨아래)를 from에서 to로 이동 
		// [2단계]
		printf("원판 1개를 %2c -> %2c로 이동하였습니다.\n", from, to);

		// 원판 n-1개 (1단계에서 옮겨진 원판)를 by에서 from을 거쳐서 to로 이동 
		// [3단계]
		tower_of_hanoi(n - 1, by, from, to);
	}
}

 

 

5. 참고자료

- 하노이의 탑 - 위키백과:  https://ko.wikipedia.org/wiki/%ED%95%98%EB%85%B8%EC%9D%B4%EC%9D%98_%ED%83%91

- '하노이의 탑' 이해하기 (feat.재귀함수) - mgyo: https://mgyo.tistory.com/185

 

728x90