遞歸方法解決漢諾塔問題(舉例說明)
問題描述
有三根杆左中右( left,mid , right ),在其中一杆( from )自下而上、由大到小按順序放置num個金盤。遊戲的目標:把該杆的金盤( from )全部移到另一杆 (to) 上,並仍保持原有順序疊好。
操作規則:每次只能移動一個盤子,並且在移動過程中三根杆上都始終保持大盤在下,小盤在上。
如圖:將左邊杆子上num個圓盤移到右邊杆子上。
由上到下爲1, 2 ,3, … ,num-1, num個盤子
舉例
from爲left, to爲mid,num爲3. (即從左邊移動三個盤子到中間)
移動方法:
move 1 from left to mid
move 2 from left to right
move 1 from mid to right
move 3 from left to mid
move 1 from right to left
move 2 from right to mid
move 1 from left to mid
遞歸方法
遞歸頭(遞歸的最底層):當num剩一個時直接將這一個移到目標to杆子上,然後返回。
遞歸體:有from(起始杆)和to(終止杆),設另一個杆子爲another,將num-1個圓盤從from移到another,再將剩餘一個最大的圓盤num移到to,最後將num-1個圓盤移到to…
輸入以及輸出
輸入移動盤子數量num,以及起始杆from和目標杆to;
輸出移動方法和移動次數。
參考代碼
import java.util.Scanner;
public class HanNuoTa {
public static void main(String[] args) {
Scanner cs = new Scanner(System.in);
System.out.print("盤子個數: ");
int num =cs.nextInt(); //輸入盤子個數
System.out.print("起始位置: ");
String from = cs.next(); //輸入起始杆,from,mid 或 right
System.out.print("終止位置: ");
String to = cs.next(); //輸入目標杆,from,mid 或 right
System.out.println(Pro(num,"left","mid","right",from,to));
}
static int Pro(int num, String left, String mid, String right, String from, String to) {
if(num<1) return 0;
else return process(num,left,mid,right,from,to);
}
static int process(int num, String left, String mid, String right, String from, String to) {
if(num==1) {
System.out.println("move "+ num +" from "+ from +" to "+ to);
return 1; //返回移動次數
}
//下面爲遞歸體,先要找到除from和to的另一個杆子
//我分爲兩步去找,如果from和to有一個是mid杆子,則另一個杆子不是left就是right
//否則,另一個杆子就是mid
//然後開始移動
if(from.equals(mid)||to.equals(mid)) {
String another = (from.equals(left)||to.equals(left))?right:left;
//找到另一個杆子another
int part1 = process(num-1,left,mid,right,from,another);
//將num-1個圓盤從from移到another
int part2 = 1;
System.out.println("move "+ num +" from "+ from +" to "+ mid);
//將剩餘一個最大的圓盤num移到to
int part3 = process(num-1,left,mid,right,another,to);
//最後將num-1個圓盤從another移到to
return part1+part2+part3; //返回移動次數
}
else {
//此時另一個圓盤就是mid
int part1 = process(num-1,left,mid,right,from,mid);
int part2 = 1;
System.out.println("move "+ num +" from "+ from +" to "+ to);
int part3 = process(num-1,left,mid,right,mid,to);
return part1+part2+part3;
}
}
}
運行
思考
現修改遊戲規則:現在限制不能從最左側的塔直接移動到最右側,也不能從最右側直接移動到最左側,而是必須經過中間。求當塔有N層的時候,打印最優移動過程和最優移動總步數。(點擊這裏查看)
個人學習經驗總結,如有問題,歡迎指正。