1. Tower of Hanoi
Artifitial Intelligence Class
Eunseok, Kim
2. Tower of Hanoi
Artifitial Intelligence Class
Eunseok, Kim
Story
3. CONTENTS / Story
인도 베나레스에 있는 한 사원에는 세상의 중심을 나타내는 큰 돔이 있고
그 안에 세 개의 다이아몬드 바늘이 동판 위에 세워져 있습니다.
바늘의 높이는 1 큐빗이고 굵기는 벌의 몸통만 합니다.
바늘 가운데 하나에는 신이 64개의 순금 원판을 끼워 놓았습니다. 가장 큰 원판이 바
닥에 놓여 있고, 나머지 원판들이 점점 작아지며 꼭대기까지 쌓아 있습니다.
이것은 신성한 브라흐마의 탑입니다. 브라흐마의 지시에 따라 승려들은 모든 원판을
다른 바늘로 옮기기 위해 밤낮 없이 차례로 제단에 올라 규칙에 따라 원판을 하나씩
옮깁니다.
이 일이 끝날 때, 탑은 무너지고 세상은 종말을 맞이하게 됩니다.
이런 전설이 있는 이유를 생각해보았습니다.
• 하노이의 탑을 푸는 가장 기본적인 방법은 재귀함수를 사용하는 방법입니다.
• 2n -1 (메르센 수) 번의 이동이 필요합니다.
• 원판의 개수가 아닌 기둥의 개수가 늘어나면 필요한 이동 회수는 기하급수적으로 줄어듭니다.
이번 과제의 목표는 먼저 어떻게 코딩하는지 설명 할 것 이며, N=64개 일 때 걸리는 회수와 그 이유를 설명하고
마지막으로 64보다 큰 수의 경우 얼마나 걸리는지 알아 볼 예정입니다.
4. Tower of Hanoi
Artifitial Intelligence Class
Eunseok, Kim
How : Recursive function
5. CONTENTS / Recursive function
• 문제는 막대 A에 쌓여있는 원판 n개를 막대 C로 옮기는 것이다.
단 다음의 조건을 지켜야 한다.
• 한 번에 하나의 원판만 이동할 수 있다
• 맨 위에 있는 원판만 이동할 수 있다
• 크기가 작은 원판위에 큰 원판이 쌓일 수 없다.
• 중간의 막대를 임시적으로 이용할 수 있으나 앞의 조건들을 지켜야 한다.
A B C
7. CONTENTS / Recursive function
n-1개의 원판
1개의 원판
A B C C를 임시버퍼로 사용하여 A에 쌓여
있는 n-1개의 원판을 B로 옮긴다.
A B C
A의 가장 큰 원판을 C로 옮긴다.
A B C
A를 임시버퍼로 사용하여 B에 쌓여
있는 n-1개의 원판을 C로 옮긴다.
A B C
8. CONTENTS / Recursive function
public class Eunseok {
public static void main(String [] ar)
{
hanoi(3, 'A', 'B', 'C'); Parameter는 순서대로 3개의 원판, 그리고 A,B,C의 타워를 나타냅니다.
}
public static void hanoi(int n, char a, char b, char c)
{
if(n < 1)
{
}else
{
hanoi(n-1, a,c,b); A에 3개의 디스크가 있다고 하고, 원판을 차례대로 움직입니다.
System.out.println(a+"->"+c);
hanoi(n-1, b,a,c);
}
}
}
A-> C
A-> B
C-> B
A-> C 3개의 원판을 움직였을 때 교수님이 말씀하신 것과 같이 7번의 이동이 필요로 합니다.
B-> A
B-> C
A-> C
9. CONTENTS /
하지만 단순히 재귀로는 이 문제를 해결 할 수 없습니다.
64개의 원반을 옮기는 Path를 구하기 위해서 새벽 1시 30분 부터 다음 날 오전 10시까지 약 9시간 가까이
프로그램을 돌렸지만 역시나 예상했던 대로 끝나지 않았습니다.
한 친구는 48시간 돌려도 프로그램이 계속 돈다라는 이야기를 해주었습니다.
대충 1번의 움직임이 1초를 걸린다고 가정하면, 64개의 원반은 5849억 4241만 7355년 정도 걸리는 것 같습니다.
PC가 빨라서 1초에 10번 연산을 한다고 해도 약 580억년이 걸립니다.
전설이 이해가 되는 이유!
50억년 후에 태양이 적색거성이 되면, 지구가 생명체가 될 수 없는
상태가 되므로 종말이라고 볼 수 있고, 하노이 탑을 옮기는 데,
5833억년 정도는 걸리므로 그 안에 모든 지구의 모든 것이 끝난다는
것은 과학적으로 타당성이 있다라고 합니다.
즉, 64개의 원반을 옮기는 횟수가 아니라 만약 그 Path를 구한다면
프로그램을 돌려도 언제 끝날 지 알 수 없습니다.
하지만, 결과를 유심히 보면 단순히 횟수는 얼마든지 구할 수 있을 것
이라는 생각이 듭니다.
10. CONTENTS /
간단하게 2, 3, 4개의 결과를 보면…
1개의 원반 일 경우 1번 움직임.
2개의 원반 일 경우 3번 움직임.
3개의 원반 일 경우 7번 움직임.
4개의 원반 일 경우 15번 움직임.
이 결과를 잘 살펴보니까 (이전회수 * 2) + 1이라는 패턴이 나옵니다.
일단 이 식이 맞는지 정확하게 판단하기 위해서는 조금 더 많은 케이스가 필요할 것 같습니다.
[1개] 1 |0*2+1
[2개] 3 |1*2+1
[3개] 7 |3*2+1
[4개] 15 |7*2+1
[5개] 31 | 15 * 2 + 1
[6개] 63 | 31 * 2 + 1
[7개] 127 | 63 * 2 + 1
[8개] 255 | 127 * 2 + 1
[9개] 511 | 255 * 2 + 1
[10개] 1023 | 511 * 2 + 1
[11개] 2047 | 1023 * 2 + 1
[12개] 4095 | 2047 * 2 + 1
[13개] 8191 | 4095 * 2 + 1
케이스가 정확하다는 판단이 서니, DP(다이나믹 프로그래밍)가 가능할 것 같다는 생각이 듭니다!
물론, Path를 알아내는 것은 힘들겠지만 단순한 필요한 횟수는 충분히 가능하리라 봅니다.
11. Tower of Hanoi
Artifitial Intelligence Class
Eunseok, Kim
Problem : DP(Dynamic programming)
12. CONTENTS / DP
위 재귀를 통하면 64개의 원판이 몇 번 만에 이동되는지는 일반적으로 얼마나 걸리는지 확인 할 수 없습니다.
실제로 3개의 타워가 아닌 4개의 타워로 64개의 원판을 옮기는데 걸린 시간은 약 6시간이 소요, 18,433번의 이동이 필요합니다
하지만, 안된다는 것으로 끝내지 않고 단순히 이동되는 경로(Path)가 아니라 몇 번의 이동이 있어야 64개를 옮길 수 있는지
수학적으로 계산하는 프로그램을 만들어보았습니다.
int i; 3
int[] hanoi = new int[64]; 7
int n; 15
hanoi[0] = 1; 31
for (i = 1; i < 64; i++) { …
hanoi[i] = hanoi[i - 1] * 2 + 1; 1073741823
System.out.println(hanoi[i]); 2147483647
} -1
< 아주 간단한 DP의 예 > < 결과는 예상과 같이 범위초과 >
13. CONTENTS / DP
32bit OS환경에서 int형은 2^32까지만 표현 할 수 있습니다. 즉, 최대로 표현할 수 있는 값은 2147483647인데 DP로 하여도
위 범위는 초과하기 때문에 -1이라는 값이 나타납니다. 이런 문제로 인해 int형으로 64개의 원반을 옮기는 코드는
일반적으로 작성할 수 없습니다. 이를 표현하기 위해 일반 int가 아닌 Big Int를 사용해보았습니다.
Java를 기준으로 long의 경우 920경 정도 표현이 가능하고, BigInteger의 경우는 사실상 거의 무한대에 가깝습니다.
public static void main(String[] args) {
while (sc.hasNext()) { 3
System.out.println(hanoi(sc.nextInt())); 7
}
sc.close();
15
} 31
public static BigInteger hanoi(int n) { …
if (n == 1) return ONE;
else
4611686018427387903
return TWO.multiply(hanoi(n - 1)).add(ONE); 9223372036854775807
} 18446744073709551615
< 이전의 공식을 BigInteger에 적용한 예 > < 64개의 원반을 이동하는 횟수 표현 >
14. CONTENTS / DP
나온 값이 정확한 값이라는 것을 증명하기 위해서 위키피디아의 내용을 가져와봤습니다.
“참고로 64개의 원판을 옮기는데 약 1844경6744조737억955만1615번을 움직여야 하고,
한번 옮길 때 시간을 1초로 가정했을때 64개의 원판을 옮기는데 5849억 4241만 7355년 걸린다.”
1844경6744조737억955만1615번
1844,6744,0737,0955,1615 번
< 위키와 동일한 횟수가 맞다는 것을 증명했습니다.>
15. Tower of Hanoi
Artifitial Intelligence Class
Eunseok, Kim
Conclusion
16. CONTENTS /
이제 마지막으로 만약 원반이 1만개였을 때 과연 몇 번의 움직임이 있어야 할까요?
(*재귀로는 앞서 말씀드린 것 처럼 절대 경로(Path)를 표시 할 수 없고, DP를 통해서 횟수만 출력해볼까 합니다.)
1만개의 원반을 옮기는데 필요한 이동 횟수는?
19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413
78111759378593209632395785573004679379452676524655126605989552055008691819331154250860846061810468550907486608962488809048989483800925
39416332578506215683094739025569123880652250966438744410467598716269854532228685381616943157756296407628368807607322285350916414761839
56381458969463899410840960536267821064621427333394036525565649530603142680234969400335934316651459297773279665775606172582031407994198
17960737824568376228003730288548725190083446458145465055792960141483392161573458813925709537976911927780082695773567444412306201875783
63255027283237892707103738028663930314281332414016241956716905740614196543423246388012488561473052074319922596117962501309928602417083
40807605932320161268492288496255841312844061536738951487114256315111089745514203313820202931640957596464756010405845841566072044962867
01651506192063100418642227590867090057460641785695191145605506825125040600751984226189805923711805444478807290639524254833922198270740
44731623767608466130337787060398034131971334936546227005631699374555082417809728109832913144035718775247685098572769379264332215993998
76886660808368837838027643282775172273657572744784112294389733810861607423253291974813120197604178281965697475898164531258434135959862
78413012818540628347664908869052104758088261582396198577012240704433058307586903931960460340497315658320867210591330090375282341553974
53943977152574552905102123109473216107534748257407752739863482984983407569379556466386218745694992790165721037013644331358172143117913
98222983845847334440270964182851005072927748364550578634501100852987812389473928699540834346158807043959118985815145779177143619698728
13145948378320208147498217185801138907122825090582681743622057747592141765371568772561490458290499246102863008153558330813010198767585
62343435389554091756234008448875261626435686488335194637203772932400944562469232543504006780272738377553764067268986362410374914109667
18557050759098100246789880178271925953381282421954028302759408448955014676668389697996886241636313376393903373455801407636741877711055
38422573949911018646821969658165148513049422236994771476306915546821768287620036277725772378136533161119681128079266948188720129864366
07685516398605346022978715575179473852463694469230878942659482170080511203223654962881690357391213683383935917564187338505109702716139
15439590991598154654417336311656936031122249937969999226781732358023111862644575299135758175008199839236284615249881088960232244362173
77161808635701546848405862232979285387562348655644053696262201896357102881236156751254333830327002909766865056855715750551672751889919
41297113376901499161813151715440077286505731895574509203301853048471138183154073240533190384620840364217637039115506397890007428536721
96280903477974533320468368795868580237952218629120080742819551317948157624448298518461509704888027274721574688131594750409732115080498
190455803416826949787141316063210686391511681774304792596709375 번이나 움직여야 합니다.
도저히 사람이 셀 수 있는 숫자는 아니라는 것은 알 수 있었습니다.
17. CONTENTS /
현존하는 프로그래밍 언어에서 표현 가능한 최대 원반의 개수는?!
(*조금 더 수학적인 언어는 다를 수 있습니다. )
원반 10,458개인 경우까지 표현 가능!!
1484891269901135553589210313941701309939510102879733255374269824920229840591492564480579633054664882224572458527395631
6501682321890030062838469605794108850277353178647593997664100182750418910980441419079530051312271486052164400236588477
7274304583063783067772138543651626933309582007090146083956475978753530571068873993489861834577505876487470946790584063
6430727238966274459036187164267253753278297907303379466286880724836422978039098012985352119440449062067971428394493578
7267545247988233378118212249473834834453810788982738745601389438595682875631562879613768038921373137028407907816450878
3863607977333400320978551950613974960645029936605335472916960876907636992248588103496512565973294979367114893104061117
0999982114878533472868893772598575429809050013720825749479033946496080359957420005327222660442249446239198252059156819
1021544901514170941795077114516885078404686108817224843547183839281757161657977324522720777265783494545219606415176224
7675258342329358574962543434461187178970888591652270601519599261734176473575158809660209579181831108529925733169534936
3068174640384401353343201353049584679060793713043982748473036499447513127521695805533883788116090758968992489553285469
1778222022174790174039021110125896415050906470102051757661927167056896111269889988056396674321609070492662695926946420
3691693916092445832701534779642342214807998184341363467970957974281253429306769883407102176932237230562531072711263713
8780285906771195971844196033521350601641015513209343768737138083901592979567843410297779862278220134379654421371377760
4909101673037123601489400383018501066484790380281969341599800658673520476868768274754084840413245730174656251436526164
9329899973110692443204626619500279833712165012207761429749841788752185880054393350593805163513768473333680419425461918
2199866862881107779618601103834700074139994524716217367625957585828664472343517415170043369283771266879313844293820461
3471595778267892501777995717990536545985418241194051798304777953469864142154348796413597199059288254795793945064175280
7504125737757381130970070088343398242774414343454868023919503676758399453316195242159373781837730667478350955044444997
9405218135546249178140238390060426259560774426962419537236713927569887305799839456214353582003470078803111568407230348
1830269157610949635294215429621306882409973791496331039725619692095673999438387504278087538764435889895167283628140984
3191585898187509290847091632830604590119411023180694493065626051643750851685846857466434734668325089759503078492346255
0696986507224742642453223989750198837251020010085710046495435709382485497700231939048684158843061108589211712580285201
5570100843846579133206279000972438068392537057564500892428132894195261092450520990469450876441742027857412434310973198
0793589354278136014183840648224742669713440682723457621602238275867177871899555640052843823269614322708140841945187982
1442552412252973098235845244157166590051516717795537236409061562818324533827424565151623105820032376926131541420706212
4451063290983046724366887943588844657970423285102320829706028569208635869713591200160363239150696860098888307942871682
955240277150253895317952505028303955604599750676875197714913356237606017243807743번의 움직임이 필요하다고 합니다.
18. CONTENTS /
• 이번 과제에 사용된 코드의 경우 아래 URL에서 다운로드 할 수 있습니다.
http://kimeunseok.com/ai
http://kimeunseok.com/ai/ha.zip