缩短一系列动作的算法?

时间:2008-11-24 06:02:54

标签: algorithm

自从我的算法在学校上课以来已经有一段时间了,所以如果我的术语不准确,请原谅我。

我有一系列操作,在运行时会产生一些所需的状态(它基本上是一组重现错误的步骤,但这对于这个问题并不重要)。

我的目标是找到仍然产生所需状态的最短步骤系列。任何给定的步骤可能都是不必要的,所以我试图尽可能有效地删除它们。

我想保留步骤的顺序(所以我可以删除步骤,但不能重新排列它们)。

我正在采取的天真方法是采取整个系列并尝试删除每个动作。如果我成功删除了一个动作(不改变最终状态),我会在系列的开头重新开始。在最坏的情况下,这应该是O(n ^ 2)。

我开始尝试提高效率的方法,但我很确定这是一个已解决的问题。不幸的是,我不确定谷歌究竟是什么 - 该系列并不是真正的“路径”,所以我不能使用路径缩短算法。任何帮助 - 甚至只是给我一些搜索条款 - 都会有所帮助。

更新:有几个人指出,即使我的天真算法也找不到最短的解决方案。这是一个很好的观点,所以让我稍微修改一下我的问题:关于同一问题的近似算法的任何想法?我宁愿有一个简短的解决方案,快速接近最短的解决方案,而不是花很长时间来保证绝对最短的系列。谢谢!

5 个答案:

答案 0 :(得分:4)

你天真的n ^ 2方法并不完全正确;在最糟糕的情况下,您可能需要查看所有子集(实际上更准确的说法是这个问题可能是NP难的,这并不意味着“可能必须查看所有子集”,但无论如何.. 。)

例如,假设您当前正在运行步骤12345,并开始尝试逐个删除它们。然后你可能会发现你不能删除1,你可以删除2(所以你删除它),然后你看1345并发现每个都是必不可少的 - 没有一个可以删除。但事实证明,如果你保持2,那么只需“125”即可。

如果你产生给定结果的集合家族不是单调的(即如果它没有属性,如果某一组行为有效,那么任何超集也是如此),那么你可以证明没有在不查看所有子集的情况下找到最短序列的方法。

答案 1 :(得分:2)

如果您对每个动作的效果没有任何假设,并且想要严格找到最小的子集,那么您将需要尝试所有可能的动作子集来找到最短的序列。

所述的二元搜索方法只有在单个步骤导致您所需的状态时才足够。

对于更一般的状态,即使一次删除一个动作也不一定会给你最短的序列。如果你考虑病态的例子,其中动作可以一起没有问题,但是单独触发你想要的状态就是这种情况。

您的问题似乎可以解决更常见的搜索问题,您可以创建的假设越多,您的搜索空间就越小。

答案 2 :(得分:2)

Delta Debugging,一种最小化一组故障诱导输入的方法,可能是一个很好的选择 我以前使用Delta(最小化“有趣”文件,基于测试的兴趣)将~1000行文件减少到大约10行,用于错误报告。

答案 3 :(得分:1)

最令人想到的是一个二元搜索启发的递归划分为两半,在这里你可以交替地忽略每一半。如果在递归的任何阶段遗漏一半仍然重现最终状态,那么将其遗漏;否则,把它重新放回并递归到那两半的 两半等等。

在两半上递归意味着它在放弃和尝试这些块的较小块之前尝试消除大块。在最坏的情况下,运行时间将是O(n log(n)),但是如果你有一个很大的n很可能有很多不相关的步骤,它应该在O(n)尝试退出的方法之前取胜每个步骤一次(但不重启)。

该算法只能找到一些最小路径,但是,由于组合的步骤间效应(如果步骤确实具有这种性质),它找不到可能存在的较小路径。但是,找到所有这些将导致组合爆炸,除非您有关于推理步骤的更多信息(例如依赖性)。

答案 4 :(得分:0)

您可以将问题域映射到方向图,其中您将状态称为节点,将步骤作为链接,您希望在图中找到最短路径,为此执行许多众所周知的算法,例如{{3} }或Dijkstra's

更新:

让我们考虑简单的情况,你有一步从状态A到状态B,这可以被绘制为由链接连接的2个节点。现在你有另一个步骤,从A到C和从C开始,你会走向导致B的步骤。有了这个你有3个节点和3个链接的图形,从A它的2到达(ACB)或1( AB)。 因此,您可以看到成本函数非常简单,您为实现目标所采取的每一步都添加1。