是否有河内塔楼的解决方案,其运行时间小于O(2 n )其中 n 是磁盘的数量移动?我的解决方案需要O(2 n )时间。
此外,下面的解决方案是递归。我们可以使用动态编程和memoization的概念在较短的时间内解决这个问题吗?
public void towersOfHanoi(
int num,
MyStack<Integer> from,
MyStack<Integer> to,
MyStack<Integer> spare
) {
if (num == 1) {
int i = from.pop();
to.push(i);
System.out.println("Move "+i+" from "+from.getName()+" to " + to.getName());
return;
}
towersOfHanoi(num - 1, from, spare, to);
towersOfHanoi(1, from, to, spare);
towersOfHanoi(num - 1, spare, to, from);
}
MyStack
是Java中Stack
类的扩展版本,它添加了name
字段和访问者。
此外,同一问题有任何变化吗?
答案 0 :(得分:17)
鉴于解决河内塔楼总是花费2 ^ n - 1步......不,你不会找到更快的算法,因为只需要打印出台阶就可以得到O(2 ^ n)少计算它们。
答案 1 :(得分:9)
我不会证明(正如史蒂芬所做的那样),但我会尝试直观地解释2 ^ n-1是min: 在每个州,磁盘只有三种可能的移动方式。 让当前状态表示为有序的seq(1,1,...,1),使得第一个数字表示较大磁盘的位置,最后一个数字表示最小磁盘的位置。 (1,1,..,1)表示所有磁盘都在位置1上。同样来自(1,1,.1)只有两个下降状态:(1,1,... 2)和( 1,1,...... 3)。从(1,1,... 2)有三种下降状态:
如果继续,您将得到节点为可能状态的图形,边缘(转换)为“磁盘移动”。
您将获得如下所示的图像(如果继续,它将看起来像三角形,顶点将是(1,1,... 1),(2,2,。。2),(3, 3,... 3))。步数实际上是图中的路径。
如果沿着三角形的边缘行走,步数为2 ^ n-1。所有其他路径长度相同或更长。
如果您使用策略:移动除最大磁盘以外的所有磁盘放置3,然后将大移动到位置2,最后将所有窗体3移动到2,可以按以下方式设计公式:
f(n)=
f(n -1)//移动除1到3之外的所有最大值
+ 1 //从1到2移动最大
+ f(n -1)//将全部从3移动到2
- &GT;
f(n)= 1+ 2 * f(n-1)
该循环方程的解决方案为您提供该策略所需的步骤数(恰好是最小步数)
答案 2 :(得分:9)
河内塔的解决方案是不可避免的2 n 。但是,在动态编程解决方案中,每个子问题只计算一次,然后通过组合第一个子问题解决方案,当前磁盘移动和第二个子问题解决方案来解决问题。
因此,生成每个解决方案有两个组件:为当前解决方案分配内存,然后填充该内存。内存分配几乎与分配的内存大小无关,是昂贵的组件。内存复制在复制的内存大小上是线性的,虽然速度很快,但在n中是指数式的,作为塔的解决方案。
时间= c 1 * n + c 2 * 2 n ,其中c 1 &gt;&gt; ; ç<子> 2 子>。即,它开始线性并以指数结束。
Link to article appearing in ACM's SIGCSE Inroads magazine (September 2012)
答案 3 :(得分:1)
河内问题的标准塔有3个钉子。
但是,如果我们有k-pegs,时间复杂度将为O(2 ^(n /(k-2)))。
我用4个钉子和5个钉子解决了这个问题,时间复杂度分别为O(2 ^(n / 2))和O(2 ^(n / 3))
答案 4 :(得分:-1)
这一步比递归快约7%。它将移动内容存储在列表中,以便您以后可以使用它,否则,可以根据需要放入打印件并删除容器。
```
unsigned long i;
static const int MAXNUMBEROFDISKS = 32;
vector<int> pow2Vec;
uint_fast32_t mPinFrom = 0;
uint_fast32_t mNumDisk = 0;
unsigned long numDiskLong = 0;
uint_fast32_t mOffset[MAXNUMBEROFDISKS];
uint_fast32_t mDir[MAXNUMBEROFDISKS] = { 0 };
uint_fast32_t mPositionDisk[MAXNUMBEROFDISKS] = { 0 };
const uint_fast32_t mRedirectArr[5] = { 2, 0, 1, 2, 0 };
Algos::Algos()
{
for (int i = 0; i < MAXNUMBEROFDISKS; ++i)
{
pow2Vec.push_back(pow(2, i));
mOffset[i] = 1;
}
for (int i = 1; i < MAXNUMBEROFDISKS; i += 2)
{
mDir[i] = 2;
}
mOffset[0] = 0;
}
void Algos::calculListBinExperiment(vector<tuple<int, int, int>>& listeFinale, int nbDisk)
{
listeFinale.resize(pow2Vec[nbDisk] - 1);
_BitScanForward(&i, nbDisk);
for (int noCoup = 1; noCoup < pow2Vec[nbDisk] ; ++noCoup)
{
_BitScanForward(&numDiskLong, noCoup);
mNumDisk = numDiskLong;
mPinFrom = mPositionDisk[mNumDisk];
mPositionDisk[mNumDisk] = mRedirectArr[mPositionDisk[mNumDisk] + mDir[mNumDisk +
mOffset[i]]];
listeFinale[noCoup - 1] = make_tuple(mNumDisk, mPinFrom, mPositionDisk[mNumDisk]);
}
}
```