Java 河内溶液塔优于O(2^n)?
对于运行时间小于O(2n)的河内塔,是否有解决方案,其中n是要移动的磁盘数?我的解需要O(2n)个时间 同样,下面的解决方案是递归的。我们能用动态规划和记忆的概念在更短的时间内解决这个问题吗Java 河内溶液塔优于O(2^n)?,java,algorithm,towers-of-hanoi,Java,Algorithm,Towers Of Hanoi,对于运行时间小于O(2n)的河内塔,是否有解决方案,其中n是要移动的磁盘数?我的解需要O(2n)个时间 同样,下面的解决方案是递归的。我们能用动态规划和记忆的概念在更短的时间内解决这个问题吗 public void towersOfHanoi( int num, MyStack<Integer> from, MyStack<Integer> to, MyStack<Integer> spare
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);
}
哈尼公共空塔(
int num,
来自,
我的目标是,
MyStack备用
) {
如果(num==1){
int i=from.pop();
推(i);
System.out.println(“将“+i+”从“+from.getName()+”移动到“+to.getName());
返回;
}
哈尼塔(数量-1,从,备用,到);
哈尼塔楼(1座,从,到,备用);
哈尼塔(数量-1,备用,至,自);
}
MyStack
是Java中Stack
类的扩展版本,它添加了name
字段和访问器
另外,同样的问题有什么变化吗?考虑到解决河内塔问题总是需要2^n-1个步骤……不,你不会找到更快的算法,因为打印出这些步骤需要O(2^n),更不用说计算了。我不会证明(像斯蒂芬那样),但我会尝试直观地解释2^n-1是最小的: 在每个状态下,磁盘只有三种可能的移动。 让我们将当前状态表示为有序的seq(1,1,…,1),这样第一个数字表示较大磁盘的位置,最后一个数字表示最小磁盘的位置。(1,1,…,1)表示所有磁盘都在位置1上。从(1,1,…1)也只有两种下降状态:(1,1,…2)和(1,1,…3)。从(1,1,…2)开始,有三种下降状态:
f(n-1)//将除最大值以外的所有值从1移动到3
+1//将最大值从1移动到2
+f(n-1)//将全部从3移动到2
->
f(n)=1+2*f(n-1)
该循环方程的解给出了该策略所需的步数(恰好是最小步数)河内塔的解不可避免地是2n。但是,在动态规划解决方案中,每个子问题只计算一次,然后通过组合第一个子问题解决方案、当前磁盘移动和第二个子问题解决方案来解决问题 因此,生成每个解决方案有两个部分:为当前解决方案分配内存,然后填充该内存。内存分配与分配的内存大小大致无关,是一个昂贵的组件。内存拷贝的大小是线性的,虽然很快,但作为塔的解决方案,它在n中是指数的 时间=c1*n+c2*2n,其中c1>>c2。也就是说,它以线性开始,以指数结束
河内的标准塔问题涉及3个木桩 然而,如果我们有k-peg,时间复杂度将是O(2^(n/(k-2)))
我用4个PEG和5个PEG解决了这个问题,得到的时间复杂度分别是O(2^(n/2))和O(2^(n/3))这个比递归的快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]);
}
}
```
```
无符号长i;
静态常量int MAXNUMBEROFDISKS=32;
向量pow2Vec;
uint\u fast32\u t mPinFrom=0;
uint\u fast32\u t mNumDisk=0;
无符号长numDiskLong=0;
uint_fast32_t mOffset[MAXNUMBEROFDISKS];
uint_fast32_t mDir[MAXNUMBEROFDISKS]={0};
uint\u fast32\u t复合磁盘[MAXNUMBEROFDISKS]={0};
consuint_fast32_t mRedirectArr[5]={2,0,1,2,0};
Algos::Algos()
{
对于(int i=0;i
“对于运行时间小于O(2^n)的河内塔,是否有解决方案,其中n是要移动的磁盘数?”-是。这被称为作弊:-)…你拿起整堆东西,一下子把它移过来。不,没有比2^n更好的遵循规则的方法。对这个主题有极好的洞察力!一开始,我并不十分方便,直到我自己从中得到灵感实现了它,然后我开始意识到示例程序和应答者都是同一个人。谢谢你,蒂姆·罗尔夫!我很幸运能在网上追踪你的踪迹。:-)您的代码不完整,但似乎CalcultiberExperiment
有一个循环,其中NoGroup
从1
运行到2^n
,其中n
是磁盘数。那是O(2^n),不是即兴表演