1
4
一般来说,你可能会被困在支付
严格的纯语言可能要付出
在这种情况下,很难看到一种机制可以利用懒惰来避免参考税。毕竟这就是为什么我们
也就是说,您可以研究是否可以使用某种板对角线拉链来利用更新的位置——利用拉链中的位置是尝试删除对数项的常用方法。 |
2
6
可能最简单的方法是使用
对于较大的n值,有三个主要选项:
|
3
3
这种方法的基本潜在问题是,每次放置皇后后,都需要修改对角线的阵列。对对角线的持续查找时间的微小改进可能不一定值得不断地创建新的修改数组的额外工作。 但了解真正答案的最好方法是尝试一下,所以我花了点时间,想出了以下几点:
这是有效的,对于n=14,大约比您提到的版本快25%。主要的加速来自使用未绑定数组
波多尼亚
推荐。与正常人
还值得尝试使用标准库中的其他数组类型,看看使用它们是否可以进一步提高性能。 |
4
3
我开始怀疑 the claim 纯函数通常是O(log n)。另请参见爱德华·凯密特的答案,这是他的说法。虽然从理论上讲,这可能适用于随机可变数组访问,但当对可重复结构(即非随机结构)进行适当研究时,随机可变数组访问可能不是大多数算法所要求的。我认为爱德华·凯密特在写“利用更新的位置”时提到了这一点。 我认为在N-Queens算法的纯函数版本中,通过为DiffArray添加一个撤消方法,O(1)在理论上是可能的,该方法要求对差异进行回首,以删除重复项并避免重放它们。 如果我对回溯N-Queens算法的运行方式的理解是正确的,那么diffarray导致的速度减慢是因为保留了不必要的差异。 在摘要中,“diffarray”(不一定是haskell的)具有(或可能具有)set element方法,该方法返回数组的新副本,并存储与原始副本的差异记录,包括指向新更改副本的指针。当原始副本需要访问元素时,必须反向重放此差异列表,以撤消对当前副本的更改。注意,在重播这个单链表之前,甚至还有一些开销需要遍历到最后。 想象一下,它们被存储为一个双链接列表,有一个如下的撤消操作。 从抽象的概念层次来看,回溯N-Queens算法所做的是递归地操作一些布尔数组,在每个递归层次上以增量方式向前移动这些数组中的皇后位置。见 this animation . 我只在脑子里想了想,diffarray之所以这么慢,是因为当皇后从一个位置移动到另一个位置时,原始位置的布尔标志被设置回“假”,新位置被设置为“真”,并且这些差异被记录下来,但是它们是不必要的,因为当反向重放时,数组以重播开始前的值结束。因此,不使用set操作将其设置回false,而是需要一个undo方法调用,也可以使用一个输入参数告诉diffarray要在上述差异的双链接列表中搜索什么“undo to”值。如果在双链接列表中的差异记录中找到“撤消到”值,则在返回列表搜索时,在同一数组元素上找不到冲突的中间更改,并且当前值等于该差异记录中的“撤消到”值,则可以删除该记录,并且可以将旧副本重新指向T他在双链表中的下一个记录。 这样做的目的是在回溯时删除整个数组不必要的复制。与强制版本的算法相比,在添加和撤消添加差异记录方面仍然存在一些额外的开销,但这可能更接近于恒定时间,即O(1)。 如果我正确地理解了n-queen算法,那么对undo操作的回首只有一个,因此没有walk。因此,在移动皇后位置时甚至不需要存储集合元素的差异,因为在访问旧副本之前,它将被撤消。我们只需要一种安全地表达这种类型的方法,这很容易做到,但是我将把它作为练习留给读者,因为这篇文章已经太长了。 更新:我还没有为整个算法编写代码,但是在我的头脑中,N-Queens可以在每个迭代行上实现,在下面的对角线数组上进行折叠,其中每个元素是:(所占行的索引或无)、与左右对角线相交的行索引数组、与之相交的行索引数组右-左对角线)。行可以使用递归或行索引数组的折叠进行迭代(折叠执行递归)。 下面是我设想的数据结构的接口。下面的语法是copute,但我认为它离scala足够近,您可以理解它的意图。 注意,如果DiffArray是多线程的,那么它的任何实现都会非常缓慢,但是N-Queens回溯算法不需要DiffArray是多线程的。感谢爱德华·凯密特在对这个答案的评论中指出了这一点。
更新:我正在处理 Scala implementation ,这有一个改进 interface 与我上面的建议相比。我还解释了对折叠的优化如何达到与可变数组相同的常量开销。 |
5
1
我有一个解决办法。然而,常数可能很大,所以我不希望打败任何东西。 以下是我的数据结构:
它允许在O(1)中执行所有必需的操作。 代码可以在这里找到: http://hpaste.org/50707
速度不好——比问题中关于大多数输入的参考解决方案要慢。我已经在输入上对它们进行了基准测试
【24.66%、19.89%、23.74%、41.22%、42.54%、66.19%、84.13%、106.30%】 注意,相对于我的参考解几乎是线性减速的,显示出渐进复杂性的差异。 我的解决方案在严格性和类似的方面可能很糟糕,必须反馈给一些非常好的优化编译器(例如DonStewart),以获得更好的结果。 无论如何,我认为在这个问题中,O(1)和O(n)无论如何都是不可区分的,因为日志(8)只是3,像这样的常量是微观优化的主题,而不是算法。 |
shampoo · 构造无重复但部分输入固定的随机化矩阵 7 年前 |
Sara Fuerst · 修复正则表达式中的灾难性回溯 7 年前 |
shibormot · 平衡组未响应的c#regex 9 年前 |
Batman · 二进制树中给定和的路径-递归|Java 9 年前 |
Eusebius · 太多的回溯:为什么这里有一个“重做”? 12 年前 |