Algorithm 优化算术表达式序列的快速算法
编辑:澄清问题描述 有没有一种快速算法可以解决以下问题? 而且,也是针对这个问题的扩展版本 这将自然数替换为Z/(2^nz)?(我认为,这个问题太复杂,无法在一个地方添加更多的问题。) 问题: 对于给定的一组自然数,如{7,20,17,100},需要算法 返回加法、多应用程序和计算幂的最短序列 所有给定的数字。 序列的每一项都是(正确的)符合以下模式的方程式:Algorithm 优化算术表达式序列的快速算法,algorithm,optimization,numbers,set,Algorithm,Optimization,Numbers,Set,编辑:澄清问题描述 有没有一种快速算法可以解决以下问题? 而且,也是针对这个问题的扩展版本 这将自然数替换为Z/(2^nz)?(我认为,这个问题太复杂,无法在一个地方添加更多的问题。) 问题: 对于给定的一组自然数,如{7,20,17,100},需要算法 返回加法、多应用程序和计算幂的最短序列 所有给定的数字。 序列的每一项都是(正确的)符合以下模式的方程式: <number> = <number> <op> <number> 我用Haskel
<number> = <number> <op> <number>
我用Haskell编写了回溯算法。 它适用于上面这样的小输入,但我真正的查询是 [0255]中随机分布了约30个数字。 对于真正的查询,以下代码在我的PC中需要2~10分钟 (,, ) 我当前的(伪)代码:
——生成计算n所需的集合集。
--集合上的运算符(+)设置为并集。
所需数字0={{}
requiredNumbers 1={{}
所需数字=
{j,k}j^k==n,j>=2,k>=2}
+{j,k}j*k==n,j>=2,k>=2}
+{j,k}j+k==n,j>=1,k>=1}
--记住最小的一组“计算”数字
最佳集:={i | 1=|最佳集|)
--剪枝
返回
其他的
m:=最小值(从)
from':=deleteMin(from)
foreach(请求输入(所需数字m))
闭包(从“+(req-to))(到+{m})
--recoverEquation是一个函数,用于将数字集转换为方程集。
--这很容易做到。
输出=恢复方程(闭包输入{})
补充说明:
答案像
- 没有快速算法,因为
- 有一个启发式算法,它是
答案#1可以作为一种启发,我认为。如果你从排序输入中的最高数字开始反向工作,检查是否/如何在其构造中使用较小的数字(以及正在引入的数字),会怎么样 例如,虽然这不能保证最短的序列
input: {7, 20, 17, 100}
(100) = (20) * 5 =>
(7) = 5 + 2 =>
(17) = 10 + (7) =>
(20) = 10 * 2 =>
10 = 5 * 2 =>
5 = 3 + 2 =>
3 = 2 + 1 =>
2 = 1 + 1
我建议将其转换为某种图最短路径算法
- 对于每个数字,计算(并存储)运算的最短路径。从技术上讲,一步就足够了:对于每个数字,可以存储运算和两个操作数(左和右,因为幂运算是不可交换的),以及权重(“节点”)
- 最初,您以0的权重注册
1
- 每次注册一个新数字时,您必须使用该数字(所有加法、乘法、幂)和所有已注册的数字生成所有计算。(“边”)
- 计算过滤器:如果计算结果已经注册,则不应存储该值,因为有一种更容易获得该值的方法
- 对于交换操作(1+2=2+1),仅存储1个操作
- 预过滤电源操作,因为这甚至可能导致溢出
- 必须将此列表排序为最短的求和路径(边的权重)。权重=(操作数1的权重)+(操作数2的权重)+(1,即操作的权重)
- 您可以排除所有大于我们必须找到的最大数的结果数(例如,如果我们已经找到100,则可以排除大于20的任何结果数)-这可以改进,以便您也可以检查操作的成员
- 如果您达到了一个目标数字,那么您找到了计算其中一个目标数字的最短方法,您必须重新开始生成:
- 重新计算目标编号的最大值
- 返回当前找到的数字的路径,将它们的权重设置为0(从现在起将给出它们,因为它们的成本已经支付)
- 重新计算生成列表中操作的权重,因为源操作数权重可能已更改(这将导致在末尾重新排序)-此处可以排除任何一个操作数大于新最大值的操作数
- 如果所有的数字都被点击,那么搜索就结束了
理论上,该算法只对每个数字进行一次处理(注册)。应用适当的过滤器会减少不必要的分支,因此不会计算两次任何内容(队列中元素的权重除外)是一个更好的提问地点。也许你可以利用这样一个事实,即你所有的运算都在增加,部分计算的数字序列也在增加。谢谢Basile。我应该在将问题发布到那里之前删除这篇文章,还是将其作为一个指针留在这里?也许使用Prolog,你可以获得更好的回溯结果。否则,我不知道我认为有一个算法解决方案。为什么你的输出也能解决不是你输入一部分的数字?你能详细说明需要做什么吗?@GaborSch,我同意,答案是“不”,我认为没有一个快速算法。无论你从“1”开始,搜索空间都会受到组合爆炸的影响或者从输入向后。似乎没有任何方法可以合理地减少搜索空间,例如,您如何为算法(如*搜索)提出合理的“距离”度量。不过,尝试解决一个更简单的问题会很有趣
-- generate set of sets required to compute n.
-- operater (+) on set is set union.
requiredNumbers 0 = { {} }
requiredNumbers 1 = { {} }
requiredNumbers n =
{ {j, k} | j^k == n, j >= 2, k >= 2 }
+ { {j, k} | j*k == n, j >= 2, k >= 2 }
+ { {j, k} | j+k == n, j >= 1, k >= 1 }
-- remember the smallest set of "computed" number
bestSet := {i | 1 <= i <= largeNumber}
-- backtracking algorithm
-- from: input
-- to: accumulator of "already computed" number
closure from to =
if (from is empty)
if (|bestSet| > |to|)
bestSet := to
return
else if (|from| + |to| >= |bestSet|)
-- cut branch
return
else
m := min(from)
from' := deleteMin(from)
foreach (req in (requiredNumbers m))
closure (from' + (req - to)) (to + {m})
-- recoverEquation is a function converts set of number to set of equation.
-- it can be done easily.
output = recoverEquation (closure input {})
input: {7, 20, 17, 100}
(100) = (20) * 5 =>
(7) = 5 + 2 =>
(17) = 10 + (7) =>
(20) = 10 * 2 =>
10 = 5 * 2 =>
5 = 3 + 2 =>
3 = 2 + 1 =>
2 = 1 + 1