指定された数値のリストと算術演算子を使用して数値を生成します


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
  • の4つの演算はすべてO、標準の数学演算です。特に、/正確な分数を持つ通常の除算です。

ポイント

  • ポイントが少ないほど良い
  • コードのすべての文字が1ポイントを与えます

読みやすい非ゴルフバージョンを提供する必要があります。

バックグラウンド

同様の質問はスタックオーバーフローに頼まれました。面白いコードゴルフの挑戦かもしれないと思った。

計算の複雑さ

ピーターテイラーがコメントで言ったように、これでサブセット和を解くことができます:

  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であることを証明します。以下のようNP対Pがあるミレニアム賞問題、ひいては1,000,000米ドルの価値が、誰かが、このためのソリューションを見つけることはほとんどありません。そこで、ランキングのこの部分を削除しました。

テストケース

有効な答えは以下だけではありません。他の解決策もあり、許可されています。

  • [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で記述できます。
ブースビー

3
使用する算術はどのようなものか–正確な分数、整数(/div)、浮動小数点および丸め誤差なし...
反時計回りの回転を停止

4
なぜ計算の複雑さのために複雑なスコアリング規則があるのですか?サブセット合計から簡単に削減できるため、O(2 ^ n)より優れたものは100万米ドルの価値があります。
ピーターテイラー


1
3番目のテストケースはFalseではありません...5+10+2*3+7*0+0...
Shmiddty

回答:


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てに評価されるようになり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)ます。このようにラムダと辞書を組み合わせようとは思っていませんでしたが、今では明らかです。
マーティントーマ

私は、4番目のテストケースでソリューションをテストしようとしました。2時間後、実行を停止しました。
マーティントーマ

@mooseヒューリスティックを追加して、高速化を試みます。ただし、その後、コード長が2倍になる場合があります。
レイ

ここで行ったように分数を使用すると、回答の問題が修正されます。私が提供したリンク上の特定のインスタンスに対して試してみてください。現在のコードでは答えが見つかりませんが、fractionを使用すると見つかります。
マーティントーマ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.