让我先举一个例子 - 我有一系列从1到9的数字。让我们说我想要的目标数是29。 在这种情况下,所需的最小操作数将是(9 * 3)+2 = 2次操作。类似地,对于18,最小操作数是1(9 * 2 = 18)。 我可以使用4个算术运算符中的任何一个 - +, - ,/和*。
如何以编程方式找出所需的最少操作数? 提前感谢您提供的任何帮助。
澄清:仅整数,中间计算不允许小数。即以下内容无效(来自以下评论):(( 9/2 )+ 1)* 4 == 22
我必须承认我没有彻底考虑这个问题,但就我的目的而言,十进制数字是否出现在计算中间并不重要。 ((9/2)+ 1)* 4 == 22有效。对不起,感到困惑。
答案 0 :(得分:4)
对于设置Y = [1..9]且n> 1的特殊情况。 0:
注意在这种情况下如何不需要分割。对于其他Y,这不成立。
该算法在log(n)中呈指数形式。对于那些对代数有更多了解的人来说,准确的分析是一项工作。
要获得更快的速度,请添加修剪以消除对较大数字的搜索。
示例代码:
def findop(n, maxlen=9999):
# Return a short postfix list of numbers and operations
# Simple solution to small numbers
if n<=9: return [n]
if n<=18: return [9,n-9,'+']
# Find direct multiply
x = divlist(n)
if len(x) > 1:
mults = len(x)-1
x[-1:] = findop(x[-1], maxlen-2*mults)
x.extend(['*'] * mults)
return x
shortest = 0
for o in range(1,10) + range(-1,-10,-1):
x = divlist(n-o)
if len(x) == 1: continue
mults = len(x)-1
# We spent len(divlist) + mults + 2 fields for offset.
# The last number is expanded by the recursion, so it doesn't count.
recursion_maxlen = maxlen - len(x) - mults - 2 + 1
if recursion_maxlen < 1: continue
x[-1:] = findop(x[-1], recursion_maxlen)
x.extend(['*'] * mults)
if o > 0:
x.extend([o, '+'])
else:
x.extend([-o, '-'])
if shortest == 0 or len(x) < shortest:
shortest = len(x)
maxlen = shortest - 1
solution = x[:]
if shortest == 0:
# Fake solution, it will be discarded
return '#' * (maxlen+1)
return solution
def divlist(n):
l = []
for d in range(9,1,-1):
while n%d == 0:
l.append(d)
n = n/d
if n>1: l.append(n)
return l
答案 1 :(得分:2)
基本思路是使用k
操作测试所有可能性,k
从0
开始。想象一下,您创建了一个高度为k
的树,该树以操作数(每个级别4 * 9个分支)为每个可能的新操作分支。在移动到下一个k
之前,您需要遍历并评估每个k
树的叶。
我没有测试这个伪代码:
for every k from 0 to infinity
for every n from 1 to 9
if compute(n,0,k):
return k
boolean compute(n,j,k):
if (j == k):
return (n == target)
else:
for each operator in {+,-,*,/}:
for every i from 1 to 9:
if compute((n operator i),j+1,k):
return true
return false
它没有考虑算术运算符的优先级和大括号,这需要一些返工。
答案 2 :(得分:2)
非常酷的问题:)
请注意,您可以从头开始!从你的例子(9 * 3)+2 = 29相当于说(29-2)/ 3 = 9。这样我们就可以避免在赛博格的回答中出现双循环。这建议使用以下算法设置Y
和结果r
:
nextleaves = {r}
nops = 0
while(true):
nops = nops+1
leaves = nextleaves
nextleaves = {}
for leaf in leaves:
for y in Y:
if (leaf+y) or (leaf-y) or (leaf*y) or (leaf/y) is in X:
return(nops)
else:
add (leaf+y) and (leaf-y) and (leaf*y) and (leaf/y) to nextleaves
这是基本的想法,性能当然可以得到改善,例如避免“回溯”,例如r+a-a
或r*a*b/a
。
答案 3 :(得分:1)
我想我的想法与Peer Sommerlund相似:
对于大数字,通过乘以大密码,你可以快速前进。
Y = 29素数?如果不是,则将其除以(2到9)的最大分频器。 否则你可以减去一个数字,以达到一个可分数。 27很好,因为它可以被9分割,所以
(29-2)/9=3 =>
3*9+2 = 29
所以也许 - 我没有考虑到这一点:搜索下一个可以被Y下方的9号整除。如果你没有达到一个数字,重复一遍。
公式是相反的步骤。
(我会尝试一些数字。:))
我试过2551,这是
echo $((((3*9+4)*9+4)*9+4))
但我没有测试每个中间结果是否是素数。 但是
echo $((8*8*8*5-9))
少了2次操作。也许我可以稍后调查一下。