通过使用给定的数字和算术运算符列表生成数字


11

系统会为您提供数字列表L = [17, 5, 9, 17, 59, 14],一包运算符O = {+:7, -:3, *:5, /:1}和一个数字N = 569

任务

输出一个方程式,该方程式L的左侧使用所有数字,而右侧使用仅数字N。如果不可能,则输出False。解决方案示例:

59*(17-5)-9*17+14 = 569

局限和澄清

  • 您不能连接数字([13,37]不能用作1337
  • 只会出现自然数和零L
  • 顺序L无关紧要。
  • 您必须使用中的所有数字L
  • 只有运营商+-*/会出现O
  • O可以拥有比您所需更多的运算符,但至少|L|-1运算符
  • 您最多可以多次使用每个运算符,直到的值O
  • 其中的所有四个运算O都是标准的数学运算;特别/是具有精确分数的正态除法。

点数

  • 点越少越好
  • 代码的每个字符都给你一点

您必须提供易于阅读的非公开版本。

背景

一个类似的问题,有人问堆栈溢出。我认为这可能是一个有趣的代码高尔夫挑战。

计算复杂度

就像彼得·泰勒(Peter Taylor)在评论中说的那样,您可以使用以下方法求解子集和

  1. 您有一个子集总和的实例(因此,有一组S和一个整数x)
  2. L:= S + [0,...,0](| S |乘以零),N:= x,O:= {+:| S | -1,*:| S | -1,/:0,-:0}
  3. 现在解决这个问题
  4. 子集总和的解决方案是不将S乘以零的数目。

如果找到比O(2 ^ n)更好的算法,则证明P = NP。由于P vs NP是一个千年奖金问题,因此价值100万美元,因此几乎没有人会找到解决方案。因此,我删除了排名的这一部分。

测试用例

以下不是唯一有效的答案,还存在其他解决方案,并且允许使用以下解决方案:

  • [17,5,9,17,59,14]{+:7, -:3, *:5, /:1}569
    => 59 * (17-5)- 9 * 17 + 14 = 569
  • [2,2]{'+':3, '-':3, '*':3, '/':3}1
    => 2/2 = 1
  • [2,3,5,7,10,0,0,0,0,0,0,0]{'+':20, '-':20, '*':20, '/':20}16
    => 5+10-2*3+7+0+0+0+0+0+0+0 = 16
  • [2,3,5,7,10,0,0,0,0,0,0,0]{'+':20, '-':20, '*':20, '/':20}15
    => 5+10+0*(2+3+7)+0+0+0+0+0+0 = 15

m = |L|吗 如果是,您如何期望运行时不依赖于该列表的大小?例如,[2,2],[+,+,...,+,/],1。实际上,由于n为O(m),您可能只用m来写。
standby

3
什么样的算法是这样使用-确切小数形式,整数(/div),只是浮点和希望换无舍入误差,...?

4
为什么复杂的评分规则会导致计算复杂?子集和有一个简单的减少,因此,比O(2 ^ n)好的任何东西都价值一百万美元。
彼得·泰勒


1
第三个测试用例不是错误的……5+10+2*3+7*0+0...
Shmiddty 2013年

Answers:


3

Python 2.7 / 478个字符

L=[17,5,9,17,59,14]
O={'+':7,'-':3,'*':5,'/':1}
N=569
P=eval("{'+l+y,'-l-y,'*l*y,'/l/y}".replace('l',"':lambda x,y:x"))
def S(R,T):
 if len(T)>1:
  c,d=y=T.pop();a,b=x=T.pop()
  for o in O:
   if O[o]>0 and(o!='/'or y[0]):
    T+=[(P[o](a, c),'('+b+o+d+')')];O[o]-=1
    if S(R,T):return 1
    O[o]+=1;T.pop()
  T+=[x,y]
 elif not R:
  v,r=T[0]
  if v==N:print r
  return v==N
 for x in R[:]:
  R.remove(x);T+=[x]
  if S(R,T):return 1
  T.pop();R+=[x]
S([(x,`x`)for x in L],[])

主要思想是使用表达式的后缀形式进行搜索。例如,2*(3+4)后缀形式为234+*。所以,这个问题成为找到的部分置换L+ O是evalates来N

以下版本是未发布的版本。堆栈stk看起来像[(5, '5'), (2, '5-3', (10, ((4+2)+(2*(4/2))))]

L = [17, 5, 9, 17, 59, 14]
O = {'+':7, '-':3, '*':5, '/':1} 
N = 569

P = {'+':lambda x,y:x+y,
     '-':lambda x,y:x-y,
     '*':lambda x,y:x*y,
     '/':lambda x,y:x/y}

def postfix_search(rest, stk):
    if len(stk) >= 2:
        y = (v2, r2) = stk.pop()
        x = (v1, r1) = stk.pop()
        for opr in O:
            if O[opr] > 0 and not (opr == '/' and v2 == 0):
                stk += [(P[opr](v1, v2), '('+r1+opr+r2+')')]
                O[opr] -= 1
                if postfix_search(rest, stk): return 1
                O[opr] += 1
                stk.pop()
        stk += [x, y]
    elif not rest:
        v, r = stk[0]
        if v == N: print(r)
        return v == N
    for x in list(rest):
        rest.remove(x)
        stk += [x]
        if postfix_search(rest, stk):
            return True
        stk.pop()
        rest += [x]
postfix_search(list(zip(L, map(str, L))), [])

1
哇,比我预期的要短。我已经编写了一个包含转换后缀<=>中缀的算法,但是我的编写并没有比您的实现短很多。令人印象深刻。并且感谢您的建设P[opr](v1, v2)。我从来没有想过将lambda和字典结合在一起,尽管现在似乎很明显。
2013年

我试图用我的第4个测试用例测试您的解决方案。2小时后,我停止了执行。
马丁·托玛

@moose我将尝试添加一些启发式方法以使其更快。但是之后,代码长度可能会加倍。

像我在这里一样使用分数,可以解决您的问题。在我提供的链接上为给定实例尝试一下。您当前的代码找不到答案,但是当您使用分数时会找到答案。
Martin Thoma 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.