编辑:澄清问题描述
是否有快速算法解决以下问题?
而且,也是针对这个问题的extendend版本
将自然数替换为Z /(2 ^ n Z)?(这个问题太复杂了,无法在一个地方添加更多问题,IMO。)
对于一组给定的自然数,如{7,20,17,100},需要算法 返回最短序列的加法,多重和幂计算 所有给定的数字。 每个序列项都是(正确的)等式,符合以下模式:
<number> = <number> <op> <number>
其中&lt; number&gt;是一个自然数,&lt; op&gt;是{+,*,^}之一。
在序列中,&lt; op&gt;的每个操作数。
应该是其中之一Input: {7, 20, 17, 100}
Output:
2 = 1 + 1
3 = 1 + 2
6 = 2 * 3
7 = 1 + 6
10 = 3 + 7
17 = 7 + 10
20 = 2 * 10
100 = 10 ^ 2
我在Haskell中写了回溯算法。 它适用于像上面这样的小输入,但我的真实查询是 在[0,255]中随机分布~30个数字。 对于真正的查询,以下代码在我的电脑中需要2~10分钟。
(Actual code, very simple test)
-- 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 {})
像
这样的答案也受到欢迎。现在我觉得没有快速准确的算法......
我认为答案#1可以用作启发式。
答案 0 :(得分:2)
如果您从排序输入中的最高数字向后工作,检查是否/如何在其构造中使用较小的数字(以及正在引入的数字),该怎么办?
例如,虽然这可能无法保证最短的序列......
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
答案 1 :(得分:2)
我建议将其转换为某种图形最短路径算法。
1
的权重为零您可以使用&#34;反向链接&#34;来构建表达式。 (每个目标数字的操作,左右操作数)。
重点是我们始终关注目标功能,即操作总数必须尽可能。为了得到这个,我们总是计算到一定数量的最短路径,然后将该数字(以及途中的所有其他数字)视为给定数字,然后将搜索扩展到剩余目标。
理论上,该算法只处理(登记)每个数字一次。应用适当的过滤器会削减不必要的分支,因此不会计算任何内容(除了队列内元素的权重)