题目
汉诺塔问题的基础上,增加限制,必须得经过中间,不能直接从左到右或从右到左,求当塔有N层的时候打印最优移动过程和最优移动总步数
要求
- 法一:递归法
- 法二:非递归法,用栈来模拟
解析
法二:非递归法,用栈实现
把左,中,右抽象成栈,分别即为ls,ms,rs,最初所有的块都在ls上,总共只能有四个动作,左到中,中到右,右到中,中到左,因为一次移动必须经过中间。每次都是从一个栈的栈顶弹出然后压入另外一个栈里。
两个原则:1>不能小压大2>相邻不可逆(当前从L->M,下一步不能从M->L)
结论:
- 第一步一定是L->M
- 在走出最少步数的过程中,四个动作只有一个动作可以满足上面的两个原则。
法二源码
public enum Action{
No,LtoM,MtoL,MtoR,RtoM
}
public int hanoiProblem2(int num,String left,String mid,String right,){
Stack<Integer> lS=new Stack<Integer>();
Stack<Integer> mS=new Stack<Integer>();
Stack<Integer> rS=new Stack<Integer>();
ls.push(Integer.MAX_VALUE);
ms.push(Integer.MAX_VALUE);
rs.push(Integer.MAX_VALUE);
for(int i=num;i>0;i--){
lS.push(i);
}
Action[] record={Action.No};
int step=0;
while(!rS.size()!=num+1){
step+=fStackToStack(record,Action.MtoL,Action.LtoM,lS,mS,left,mid);
step+=fStackToStack(record,Action.LtoM,Action.MtoL,mS,lS,mid,left);
step+=fStackToStack(record,Action.RtoM,Action.MtoR,mS,rS,mid,right);
step+=fStackToStack(record,Action.MtoR,Action.RtoM,rS,mS,right,mid);
}
return step;
}
public static int fStackToStack(Action[] record, Action preNoAct,Action nowAct,Stack<Integer> fStack,Stack<Integer> tStack,String from,String to){
if(record[0]!=preNoAct&&fStack.peek(),tStack.peek()){
tStack.push(fStack.pop());
System.out.println("Move "+tStack.peek()+" from "+from+" to "+to);
record[0]=nowAct;
return 1;
}
return 0;
}
这道题有点难,欢迎大家交流讨论~