我很想知道towers of Hanoi拼图中给定移动的每个挂钩上有多少个磁盘。例如,给定n = 3
个磁盘,我们有这个配置序列,以便最佳地解决难题:
0 1 2
0. 3 0 0
1. 2 0 1 (move 0 -> 2)
2. 1 1 1 (move 0 -> 1)
3. 1 2 0 (move 2 -> 1)
4. 0 2 1 (move 0 -> 2)
5. 1 1 1 (move 1 -> 0)
6. 1 0 2 (move 1 -> 2)
7. 0 0 3 (move 0 -> 2)
所以给出5号移动,我想返回1 1 1
,给出6号移动,我想要1 0 2
等。
这可以通过使用经典算法轻松完成,并在一定数量的移动后停止,但我想要更高效的东西。我上面链接的维基百科页面提供了Binary solutions
部分下的算法。我认为这是错误的。我也不明白他们如何计算n
。
如果您按照他们的示例转换磁盘位置,则返回到我想要的位置,它会为4 0 4
磁盘提供n = 8
并移动号码216
。然而,使用经典算法,我得到4 2 2
。
还有一种在C here中实现的高效算法,它也提供4 2 2
作为答案,但它没有文档,我无法访问它基于的文章。
上一个链接中的算法似乎是正确的,但任何人都可以解释它是如何工作的吗?
我也感兴趣的一些相关问题:
n
?答案 0 :(得分:1)
1)如果你的算法说维基百科坏了,我猜你是对的......
2)至于计算每个挂钩中的磁盘数量,为它做一个递归算法是非常直接的:
(未经测试,不优雅且可能充满+ -1错误代码如下:)
function hanoi(n, nsteps, begin, middle, end, nb, nm, ne)
// n = number of disks to mive from begin to end
// nsteps = number of steps to move
// begin, middle, end = index of the pegs
// nb, nm, ne = number of disks currently in each of the pegs
if(nsteps = 0) return (begin, middle, end, nb, nm, ne)
//else:
//hanoi goes like
// a) h(n-1, begin, end, middle) | 2^(n-1) steps
// b) move 1 from begin -> end | 1 step
// c) h(n-1, middle, begin, end) | 2^(n-1) steps
// Since we know how the pile will look like after a), b) and c)
// we can skip those steps if nsteps is large...
if(nsteps <= 2^(n-1)){
return hanoi(n-1, nsteps, begin, end, middle, nb, ne, nm):
}
nb -= n;
nm += (n-1);
ne += 1;
nsteps -= (2^(n-1) + 1);
//we are now between b) and c)
return hanoi((n-1), nsteps, middle, begin, end, nm, nb, ne);
function(h, n, nsteps)
return hanoi(n, nsteps, 1, 2, 3, n, 0, 0)
如果你想要效率,它应该尝试将其转换为迭代形式(不应该很难 - 你不需要保持堆栈)并找到一种方法来更好地表示程序的状态,而不是不再使用6+变量。
答案 1 :(得分:1)
你可以利用两个权力位置很容易知道的事实。对于T大小的塔,我们有:
Time Heights
2^T-1 | { 0, 0, T }
2^(T-1) | { 0, T-1, 1 }
2^(T-1)-1 | { 1, T-1, 0 }
2^(T-2) | { 1, 1, T-2 }
2^(T-2)-1 | { 2, 0, T-2 }
2^(T-2) | { 2, T-3, 1 }
2^(T-2)-1 | { 3, T-3, 0 }
...
0 | { T, 0, 0 }
很容易找出你的行动k在哪个等级之间;只需看看log2(k)。
接下来,注意在2 ^(a-1)和2 ^ a-1之间,有T-a磁盘停留在同一个地方(最重的磁盘)。然而,所有其他块都将移动,因为在此阶段算法正在移动大小为a的子功率。因此,使用迭代方法。
让书籍保持正确可能有点棘手,但在这里你可以找到任何k的高度,时间复杂度为O(log2(T))。
干杯
答案 2 :(得分:0)
If you look at the first few moves of the puzzle, you'll see an important pattern. Each move (i - j) below means on turn i, move disc j. Discs are 0-indexed, where 0 is the smallest disc.
1 - 0
2 - 1
3 - 0
4 - 2
5 - 0
6 - 1
7 - 0
8 - 3
9 - 0
10 - 1
11 - 0
12 - 2
13 - 0
14 - 1
15 - 0
光盘0每转2圈,从第1个开始移动。光盘1每4圈移动一次,从第2个开始...光盘i每2 ^(i + 1)圈移动,从第2轮开始^岛
因此,在恒定时间内,我们可以确定给定光盘移动了多少次,给定m:
移动=(m + 2 ^ i)/(2 ^(i + 1))[整数除法]
接下来要注意的是每张光盘都以循环模式移动。即,奇数盘每次移动时向左移动(2,3,1,2,3,1 ......),偶数盘向右移动(1,3,2,1, 3,2 ......)
因此,一旦您知道光盘移动了多少次,您就可以通过采用模式3(并进行一些计算)轻松确定它结束的钉子。