برج هانوی

برج هانوی (در بعضی منابع « برج‌های هانوی ») از سه میله و تعدادی دیسک در اندازه‌های متفاوت تشکیل شده‌است که می‌توان آن‌ها را بر میله‌ها جای داد.
تاریخچه و صورت مسئله
در محوطه معبدی در آسیای دور سه میله الماسی قرار داشت که یکی از آن‌ها حاوی تعدادی قرص طلایی بود. کاهنان معبد در تلاش بودند تا قرص‌های طلائی را از آن میله به یکی دیگر از میله‌ها تحت شرایطی انتقال دهند، و باور داشتند که با تمام شدن انتقال قرص‌ها عمر جهان نیز به پایان خواهد رسید! میله اولیه ۶۴ قرص داشت، که بر روی هم به‌طور نزولی بر اساس اندازه‌شان چیده شده‌بودند.
نمونه‌ای از برج هانوی
همانند شکل سه میله داریم. یکی از میله‌ها میله مبدا (A)، دیگری میله کمکی (B) و دیگری میله مقصد (C) است. هدف انتقال تمام دیسک‌ها از میله مبدا به میله مقصد با رعایت شرایط زیر است:
در هر زمان فقط یک دیسک را می‌توان جابجا نمود.
نباید در هیچ زمانی دیسکی بر روی دیسک با اندازه کوچکتر قرار بگیرد.
حل معادله
هدف ما ارائه الگوریتمی است که کمترین توالی حرکت‌ها را برای انتقال دیسک‌ها به ما بدهد. مثلا اگر n=۲ باشد، توالی حرکت به صورت زیر است:
حل مسئله برج هانوی با ۴ دیسک
دیسک ۱ را به میله B منتقل می‌کنیم.
دیسک ۲ را به میله C منتقل می‌کنیم.
دیسک ۱ را به میله C منتقل می‌کنیم.
حل مسئله برج هانوی با ۳ دیسک
توجه داشته باشید که بر اساس قانون اول نمی‌توان به غیر از بالاترین دیسک هر میله، به دیسک دیگری از آن دسترسی پیدا کرد.
حال سوال این است که آیا این مسئله به کمک تکنیک بازگشت قابل حل است؟ اصولا چه مسائلی را می‌توان بازگشتی حل نمود؟
برای اینکه مسئله‌ای بتواند با روش بازگشتی حل شود باید یک ویژگی اساسی داشته باشد. مسئله اصلی (مسئله‌ای که به ما داده می‌شود) قابل خرد شدن به زیر مسئله‌هایی از همان نوع مسئله اصلی باشد، به شرطی که اندازه زیر مسئله‌های ایجاد شده کمتر باشد. آنگاه می‌توان امیدوار بود که آن را به‌طور بازگشتی حل کرد! این ویژگی در مورد مسئله برج هانوی صدق می‌کند. ایده اصلی این است که توجهمان را به جای حرکت بالاترین دیسک، روی پایین‌ترین دیسک میله متمرکز کرده، و مراحل زیر را طی می‌کنیم:
n - ۱ دیسک بالایی را با شرایط ذکر شده و به کمک میله C به میله B منتقل می‌کنیم.
بزرگترین دیسک را از میله مبدا به میله مقصد حرکت می‌دهیم.
n - ۱ دیسک را که هم اکنون در میله B هستند با شرایط داده شده به میله مقصد انتقال می‌دهیم. می‌بینیم که توانستیم عملیات جابجا کردن n دیسک را به دو عملیات مشابه ولی با اندازه کمتر و یک عملیات ساده تقسیم کنیم. واضح است که جابجا کردن n - ۱ قرص راحتتر از جابجا نمودن n قرص است.
برج هانوی به زبان ++C
تابع بازگشتی زیر به زبان ++C ترتیب حرکت‌ها را چاپ می‌کند:
void hanoi ( int nDisk, char start, char temp, char finish )
if ( nDisk == 1 )
cout "
0 )
if( moving disk succeeds )
if( disk == max )
max--;
if( max == 0 )
return;
dest = the final place of max;
else
dest = the alternative place between dest and the current place of disk;
disk--;
p and q = the places different of dest;
disk = the smaller of the disks on top of p and q;
dest = the place between p and q with greater disk on top;
در پایان توجه داشته باشید که دو روش ذکر شده، تنها روش‌های پیاده‌سازی غیربازگشتی حل مسئله نیستند.
برنامه برج هانوی به زبان c:
include
include
define COUNT 8
enum Bar{L,C,R;
struct disk{int Size,Color;;
struct stack{int i; disk *Disks;;
void transfer(int,Bar,Bar,Bar);
void init(); // Init bars
void MoveDisk(Bar from,Bar to);
void DrawBars();
stack Bars3={ {0,{0 ,{0,{0, {0,{0 ;
int main(void)
textmode(C4350);
clrscr();
init();
DrawBars();
transfer(COUNT,L,R,C);
getch();
return 0;
char ConvertBarEnum2Char(Bar E){
char r=0;
switch (E) {
case L: r=L; break;
case C: r=C; break;
case R: r=R; break;
return r;
void msg(Bar from,Bar to){
gotoxy(25,4);
textattr(15|16*0);
cprintf("Press anykey to move from %c to %c",ConvertBarEnum2Char(from),ConvertBarEnum2Char(to));
gotoxy(37,5);
cprintf("Esc = Exit");
void transfer(int n,Bar from,Bar to,Bar temp){
if(n>0){
transfer(n-1,from,temp,to);
msg( from, to);
MoveDisk(from,to);
transfer(n-1,temp,to,from);
void init(){
BarsL.Disks=new diskCOUNT;
for(int i=0;i<COUNT;i++){
BarsL.Disksi.Size=COUNT-i+1;
BarsL.DisksCOUNT-i-1.Color=i+1;
BarsL.i=COUNT-1;
BarsR.Disks=new diskCOUNT;
for(i=0;i<COUNT;i++){
BarsR.Disksi.Size=0;
BarsR.Disksi.Color=0;
BarsR.i=-1;
BarsC.Disks=new diskCOUNT;
for(i=0;i<COUNT;i++){
BarsC.Disksi.Size=0;
BarsC.Disksi.Color=0;
BarsC.i=-1;
void MoveDisk(Bar from,Bar to){
char kb=getch();
if(kb==27) exit(1);
Barsto.Disks = Barsfrom.Disks ;
clrscr();
DrawBars();
void me(){
char c;
for(int i=0;stri;i++){
c=i%14+1;
if(c==1)c=2;
textattr(c|16);
cprintf("%c",stri);
void DrawBars(){
int n=0;
for(int j=0;j<3;j++){
for(int i=0;i<=Barsj.i;i++){
gotoxy(1+j*27,24-i);
textattr(Barsj.Disksi.Color|16*0);
for(n=0;n<28 -- n-13<Barsj.Disksi.Size ;n++){
if(n<14-Barsj.Disksi.Size)
cprintf("%s"," ");
else
cprintf("%s","");
textattr(15|16*0);
for(n=0;n<15;n++){
gotoxy(1+j*27+13,n+10);
cprintf("%s","؛");
gotoxy(5,28);
me();