我想解决河内塔的任意(但有效)输入。
例如,我有一个有3张光盘的游戏:
A B C
| | |
| | 1
| 3 2
维基百科上给出的迭代和递归算法因此输入失败。递归停止在错误的位置或尝试非法移动而迭代的移动不会终止。
是否有“简单”的算法来解决这个问题? 我发现的唯一其他问题是Towers of Hanoi - giving help to the user mid game,而且这两个答案都没有帮助。
答案 0 :(得分:1)
对于维基百科上的解决方案:它们只是用于将堆栈从一个引脚移动到另一个引脚,而不是用于任何输入。您可以考虑使用一些路径查找算法(适用于任何有效输入和预期输出)。
define state := a state of the hanoi tower (the positions of all elements on the pins).
define listMoves := returns a list of all valid moves that can made from the specified state
define solve:
input: state start , state end
output: void
list visited
list nextStates
add(nextStates , start)
while NOT isEmpty(nextStates)
state s = remove(nextStates , 0)
if s == end
return
add(visited , s)
for state n : listMoves(s)
if NOT contains(visited , n)
add(nextStates , n)
add(visited , n)
这只是一些简单的BFS。你也可以使用Dijkstra或A *。
答案 1 :(得分:0)
简单但效率不高的答案:
首先在较小的问题上运行算法以获得更大的标准,然后在更大的问题上运行算法
在给定的示例中,您将运行SolveHanoi(2, C, B)
然后SolveHanoi(3, B, A)
将所有三张光盘从给定状态移动到A.
更有效的解决方案:
请注意,递归解决方案(如果我的记忆服务正确)会针对较小的问题运行算法,移动一张光盘,然后针对相同的小问题运行算法,稍有不同。
我建议您尝试(或以某种方式检查),运行原始算法,但不是全部 - 只需要从您给定的状态运行的部分。
<强>澄清:强>
看一下这个例子,想一想:
如果有一个游戏,所有光盘都在轮询B上,你需要将它们移动到A,算法将:
1.移动光盘1&amp; 2至C.
2.将3移至A.
3.移动1&amp; 2到A.
您获得的输入是阶段#1之后的状态。
您的解决方案应该这样做:
1.实现什么是可能的初始状态(没有太多的选择,因为有三个民意调查开始)
2.在NOT-REAL-OP模式下运行递归算法(实际上不做任何动作),直到达到给定状态
3.继续以REAL-OP模式运行算法。
希望这有用。
答案 2 :(得分:0)
好吧,我说有一个&#34; easy&#34;算法:蛮力,递归搜索所有可能的移动,直到找到目标状态。那&#34;容易&#34;作为算法,但可能需要一些时间来处理,具体取决于您的问题的大小。此外,对于使用m个光盘的n个堆,可能存在可能的状态,因此更大的谜题可能会遇到内存问题。
例如,使用Dijkstra's algorithm:
然后你可以使用&#34; infinite graph&#34;优化以避免必须在初始化阶段枚举所有状态。
归结为实际问题,我认为主要问题是&#34;存储董事会状态的最佳方式是什么?&#34;。为了清晰起见,我在这里使用了略有不同的例子(3个桩,4个碟片):
A B C
| | |
| 3 1
| 4 2
对电路板进行建模的一种简单方法是为每个堆设置一个整数数组,每个数组包含该堆上的光盘数:
A -> []
B -> [3,4]
C -> [2,1]
然而,我的第一直觉是反过来,只存储一个包含每个光盘所在的堆的数组(1在C上,2在C上,3在B上,4在B上) ):
Discs = [C,C,B,B] // four entries, one for each disc
这完全捕获单个数组中的板状态,并且易于比较(如果需要,您可以在此处存储单个字符串:&#34; CCBB&#34;)。
要计算下一个可能的移动,只需要遍历数组:第一次看到一个字母,那是该堆上最小的光盘(A上没有任何东西,3位于B的顶部,1位于C)的顶部:
Piles = [0,3,1] // three entries - one for each pile
然后你可以将任何条目移动到空堆(0)或更大的数字,因此可能的移动是:
3 -> 0 : B -> A : Discs[3] = "A" // move disc 3 from B to A giving [C,C,A,B]
1 -> 0 : C -> A : Discs[1] = "A" // move disc 1 from C to A giving [A,C,B,B]
1 -> 3 : C -> B : Discs[1] = "B" // move disc 1 from C to B giving [B,C,B,B]
我想如果我真的写了这篇文章,我可能最终会在每个堆上缓存最小的光盘以保存每次重新计算它,但这个想法是一样的。
祝你好运。答案 3 :(得分:0)
河内迭代解决方案塔 import java.util.Arrays;
公共课TowerOfHanoi {private static int SIZE = 5;
private class stack {
stack(int size) {
dataElements = new int[size];
}
int[] dataElements;
int top = -1;
private void push(int element) {
dataElements[++top] = element;
}
private int pop() {
if(top==-1) {
return -1;
}
int topEle = dataElements[top];
dataElements[top]=0;
top --;
return topEle;
}
private int top() {
if(top==-1) {
return -1;
}
return dataElements[top];
}
private boolean isEmpty() {
return top == -1;
}
}
public static void main(String[] args) {
towerOfHanoi(SIZE);
}
private static void towerOfHanoi(int number) {
initialize(number);
if(number % 2 == 0) {
solveEven(number);
} else {
solveOdd(number);
}
}
private static int recentMoved = -1;
private static stack source = new TowerOfHanoi().new stack(SIZE);
private static stack intermediate = new TowerOfHanoi().new stack(SIZE);
private static stack destination = new TowerOfHanoi().new stack(SIZE);
private static void solveEven(int number) {
while(destination.top < number-1) {
if(!movePlates(source, intermediate, destination)) {
if(!movePlates(intermediate,destination,source)) {
if(!movePlates(destination, source, intermediate)){
continue;
}
}
}
}
}
private static boolean movePlates(stack from , stack dest1 ,stack dest2) {
boolean movedPlate = false;
if(from.top()== recentMoved) {
return movedPlate;
}
if((!from.isEmpty()) && from.top()<(dest1.top()==-1?10000:dest1.top())) {
dest1.push(from.pop());
recentMoved=dest1.top();
movedPlate = true;
}
else if((!from.isEmpty()) && from.top()<(dest2.top()==-1?10000:dest2.top())){
dest2.push(from.pop());
recentMoved=dest2.top();
movedPlate = true;
}
if(movedPlate)
display();
return movedPlate;
}
private static void display() {
Arrays.stream(source.dataElements).forEach(System.out::print);
//.stream().fl.forEach(System.out::print);
System.out.print("\t");
Arrays.stream(intermediate.dataElements).forEach(System.out::print);
System.out.print("\t");
Arrays.stream(destination.dataElements).forEach(System.out::print);
System.out.print("\n");
}
private static void initialize(int number) {
for(int i=number;i>0;i--) {
source.push(i);
}
}
private static void solveOdd(int number) {
while(destination.top < number-1) {
if(!movePlates(source, destination, intermediate)) {
if(!movePlates(destination,intermediate,source)) {
if(!movePlates(intermediate, source, destination)){
continue;
}
}
}
}
}
}