하노이탑 이동 순서 (boj.kr/11729)
문제 해설 및 주의사항
- 하노이 탑의 최소 이동 순서를 출력하는 프로그램을 작성하자.
- 첫 번째 장대에 쌓인 원판의 개수 N 이 주어진다.
해설
적용한 레시피 / 방법론 + 접근법
풀이
1. 규칙을 찾아보자.
- m 개의 원판을 3번째 장대로 옮긴다고 해보자. 그렇다면,
1. 먼저 위의 m - 1개의 원판을 2번째 장대로 옮기고 ( a_(m-1) )
2. 남은 1개의 원판을 3번째 장대로 옮기고 ( + 1)
3. 2번째 장대의 m - 1 개 원판을 3번째 장대로 옮긴다. ( a_(m-1) )
최단 이동 횟수의 점화식은
a_n = 2a_(n - 1) + 1
이 될 것이다.
2. 함수의 구현
- 재귀를 호출 할 때 달라지는 것은 무엇일까
a. 목적지 장대 ( 1, 2, 3 중 하나 ) (end)
b. 출발지 장대 ( start)
b. 원판의 갯수 (num)
풀이코드
#include <iostream>
#include <algorithm>
using namespace std;
// 1780 종이의 개수
vector<pair<int, int>> ans;
int solve(int num, int start, int end){
if(num == 1){
ans.push_back(make_pair(start, end));
return 1;
}
int ret = 0;
// 1. 먼저 위의 m - 1개의 원판을 2번째 장대로 옮기고 ( a_(m-1) )
ret += solve(num - 1, start, 6 - (start + end));
// 2. 남은 1개의 원판을 3번째 장대로 옮기고 ( + 1)
ret += solve(1, start, end);
//3. 2번째 장대의 m - 1 개 원판을 3번째 장대로 옮긴다. ( a_(m-1) )
ret += solve(num - 1, 6 - (start + end), end);
return ret;
}
int main(){
int n;
cin >> n;
cout << solve(n, 1, 3) << endl;
for(pair<int,int> p : ans){
printf("%d %d\n",p.first, p.second);
}
}
아쉬웠던 부분 / 오답 원인 / 개선해야 할 점
1. 출력 형식의 잘못
- 처음 제출할 때, 이동 순서를 먼저 출력하였다. 최소 이동 횟수 출력 후 이동 순서를 출력해야 한다는 점을 유의했어야 했다.
2. 분할 정복이란?
- 결국 문제를 어떻게 분할 하는 것이냐가 관건이다. 그렇게 하기 위해서는 함수를 구현할 때, 파라미터로 무엇을 넣어야 하는지 부터 잘 생각해보아야 하며, 코드 짜는 것에 돌입하기 전에 문제를 분할하는 과정들을 세세히 말해두어야 한다.
위의 글에서 나눈 것처럼 재귀함수에서도 똑같이 분할하였더니 답이 나왔다.
반응형
'ps > 분할 정복' 카테고리의 다른 글
[분할 정복] 사분면 1891 (0) | 2021.10.21 |
---|---|
[분할 정복] Z 1074 ○ (0) | 2021.10.16 |
[분할 정복] 트리의 순회 2263 ○ (0) | 2021.10.16 |
종이의 개수 (boj.kr/1780) (0) | 2021.10.14 |