알고리즘문제풀이

백준 23250 하노이 탑 K

배우겠습니다 2023. 12. 16. 01:29

문제

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

 

23250번: 하노이 탑 K

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

www.acmicpc.net

 

하노이탑은 다음과 같은 기본로직에서 출발한다.

원판이 1~N개 있을때 

1. 1~N-1 묶음을 1번에서 2번막대로 옮긴다.

2. N번 원판을 1번에서 3번으로 옮긴다.

3. 1~N-1 묶음을 2번에서 3번으로 옮긴다.

따라서 원판이 N개인 하노이탑을 옮기는 횟수 F(N) = F(N-1) + 1 + F(N-1) = 2^N - 1이다.

이것을 기본 하노이탑 코드로 제출할시 2^60이란 어마무시한 숫자를 감당못하므로 시간이 초과날 것이다.

F(N) = T라고 하고 F(N-1)이 T'이라 하면,

1번째에서 T'-1번까지는 1~N-1묶음을 1번에서 2번막대로 옮기는 과정이다.

T'번째는 N번원판을 1번에서 3번으로 옮기는 과정이다.

T'+1번째~T번째는 1~N-1묶음을 2번에서 3번으로 옮기는 과정이다.

만약에 1<= K <=T'-1이라하자.

그러면 T'+1~T번째 움직임을 굳이 볼 필요가 있을까?

마찬가지로 K == T'이라면 or T'+1 <= K <= T라면 굳이 다른 과정을 볼 필요가 있을까?

그럴 필요 없다.

F(N) = F(N-1) + 1 + F(N-1)이므로, log2(2^N-1)의 복잡도로 빠르게 계산할 수 있다.

절반의 움직임을 날리기 떄문이다.

 

필요한 정보는 다음과 같다.

 

getTot(int N) 또는 cnt[N]: N개의 원판묶음을 옮기는데 필요한 총 움직임 수

getTot은 2^N-1을 넣어주고 cnt의 원소도 마친가지로 구해준다.

 

solve()함수

solve함수의 param

s1: 시작 막대, s2:경유 막대, s3:목적 막대

우린 원판묶음을 s1->s3로 옮길 것이다.

start,end: 현재 보고 있는 움직임의 범위

cnt: 현재 옮기는 원판 묶음의 크기

 

func solve(int s1,int s2,int s3,ll start,ll end,int scale){
	ll half = cnt[scale-1];
    ll part1 = start + half - 1;
    ll mid = start + half;
    ll part2 = start + half + 1; 
    if (K <= part1){
    	return solve(s1,s3,s2,start,part1,scale-1);
    } else if (K == mid{
    	return [s1,s3]; // result
    } else if (K >= part2{
    	return solve(s2,s1,s3,part2,end,scale-1);
    }
}
print(solve(1,2,3,1,cnt[N],N);