【题目】
汉诺塔问题比较经典,这里修改一下游戏规则:现在限制不能从最左侧的塔直接移动到最右侧,也不能从最右侧直接移动到最左侧,而是必须经过中间。求当塔有N层的时候,打印最优移动过程和最优移动总步数。
【代码实现】
class Demo{
public static void main(String[] args){
int i = hanoi(3,"a","b","c","a","c");
System.out.println("总步数:" + i );
}
//num表示盘子的总数,left是左边的柱子,mid是中间的柱子,right是右边的柱子,from是起始的柱子,to是终止的柱子
public static int hanoi(int num,String left,String mid,String right,String from,String to){
//盘子数目小于1的时候,不用移动,返回步数为0
if(num<1){
return 0;
}
//如果只剩下一个最顶层的盘子,分两种情况,递归的终止条件
if(num==1){
//如果起始柱子是中间或者终止柱子是中间,那么只用移动一步就好
//如果起始柱子和终止柱子都不是中间,那么根据题目,就需要先从起始移动到中间,再从中间移动到右边,也就是需要移动两步
if(from.equals(mid) || to.equals(mid)){
System.out.println("move" + num + " " + from + "->" + "to" );
return 1;
}else{
System.out.println("move" + num + " " + from + "->" + mid);
System.out.println("move" + num + " " + mid + "->" + to);
return 2;
}
}
//如果剩余的盘子数量大于1,分两种情况
//情况一:
//如果起始柱子是中间或者终止柱子是中间,那么需要三步
//第一步:将第1 — num-1个盘子从起始柱子移动到临时柱子,用递归实现
//第二步:将第num个盘子从起始柱子移动到终止柱子
//第三步:将第1 — num-1个盘子从临时柱子移动到终止柱子,用递归实现
//最后返回三步的步数总和
//情况二:
//如果起始柱子和终止柱子不是中间,那么无非就是从最左边的柱子移动到最右边的柱子或者从最右边的柱子移动到最左边的柱子,那么需要五步
//第一步:将第1 — num-1个盘子从起始柱子移动到终止柱子,用递归实现
//第二步:将第num个盘子从起始柱子移动到中间的柱子(因为中间一定是空的)
//第三步:将第1 — num -1个盘子从终止柱子移动到起始柱子,用递归实现
//第四步:将第num个盘子从中间柱子移动到终止柱子
//第五步:将第1 — num-1个盘子从起始柱子移动到终止柱子
if(from.equals(mid) || to.equals(mid)){
//another用来确定那个是临时的柱子
String another = (from.equals(left) || to.equals(left))?right:left;
int part1 = hanoi(num-1,left,mid,right,from,another);
int part2 = 1;
System.out.println("move" + num + " " + from + "->" + to);
int part3 = hanoi(num-1,left,mid,right,another,to);
return part1+part2+part3;
}else{
int part1 = hanoi(num-1,left,mid,right,from,to);
int part2 = 1;
System.out.println("move" + num + " " + from + "->" + mid);
int part3 = hanoi(num-1,left,mid,right,to,from);
int part4 = 1;
System.out.println("move" + num + " " + mid + "->" + to);
int part5 = hanoi(num-1,left,mid,right,from,to);
return part1+part2+part3+part4+part5;
}
}
}