สร้างตัวเลขโดยใช้รายการตัวเลขและตัวดำเนินการทางคณิตศาสตร์ที่ระบุ


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 | คูณ a zero), N: = x, O: = {+: | S | -1, *: | S | - 1, /: 0, -: 0}
  3. ตอนนี้แก้ปัญหาของฉันตัวอย่างนี้
  4. วิธีแก้ปัญหาสำหรับผลรวมย่อยคือจำนวนของ S ที่ไม่ได้คูณด้วยศูนย์

หากคุณพบอัลกอริทึมที่ดีกว่า O (2 ^ n) คุณจะพิสูจน์ได้ว่า P = NP เนื่องจากP vs NPเป็นปัญหาของรางวัลมิลเลนเนียมและมีมูลค่า 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|อะไร ถ้าใช่คุณคาดหวังว่า runtime จะไม่ขึ้นอยู่กับขนาดของรายการนั้นอย่างไร ตัวอย่างเช่น[2,2],[+,+,...,+,/],1. อันที่จริงแล้วเนื่องจาก n คือ O (m) คุณอาจเขียนมันทั้งหมดในรูปของ m
บูธตาม

3
การคำนวณทางคณิตศาสตร์แบบไหนที่จะใช้ - เศษส่วนที่แน่นอนจำนวนเต็ม ( /div) เพียงจุดลอยตัวและความหวังแบบไม่มีข้อผิดพลาดการปัดเศษ ... ?
หยุดหมุนทวนเข็มนาฬิกาเมื่อ

4
ทำไมกฎการให้คะแนนที่ซับซ้อนสำหรับความซับซ้อนในการคำนวณ? มีการลดลงอย่างง่ายดายจากผลรวมย่อยดังนั้นสิ่งที่ดีกว่า O (2 ^ n) มีค่านับล้านเหรียญสหรัฐ
Peter Taylor

1
ที่เกี่ยวข้อง: stackoverflow.com/questions/3947937/…
Dr. belisarius

1
กรณีทดสอบที่ 3 ไม่ใช่เรื่องเท็จ ...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],[])

แนวคิดหลักคือการใช้รูปแบบ postfix ของนิพจน์เพื่อค้นหา ยกตัวอย่างเช่น2*(3+4)ในรูปแบบ postfix 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
ว้าวสั้นกว่าที่ฉันคาดไว้ ฉันได้เขียนอัลกอริทึมซึ่งรวมถึง postfix การแปลง <=> มัด แต่ Scribble ของฉันไม่สั้นกว่าการใช้งานของคุณมาก ที่ประทับใจ P[opr](v1, v2)และขอขอบคุณสำหรับการก่อสร้าง ฉันไม่เคยคิดที่จะรวบรวมแลมบ์ดาและพจนานุกรมเช่นนี้มาก่อน
Martin Thoma

ฉันพยายามทดสอบโซลูชันของคุณด้วย testcase ที่ 4 ของฉัน หลังจาก 2 ชั่วโมงฉันหยุดการประหารชีวิต
Martin Thoma

@moose ฉันจะพยายามเพิ่มฮิวริสติกบางอย่างเพื่อให้เร็วขึ้น แต่หลังจากนั้นความยาวรหัสอาจเป็นสองเท่า
เรย์

การใช้เศษส่วนเหมือนที่ฉันทำที่นี่ช่วยแก้ปัญหาในคำตอบของคุณ ลองทำตามอินสแตนซ์ที่ระบุในลิงก์ที่ฉันให้ไว้ รหัสปัจจุบันของคุณไม่พบคำตอบ แต่เมื่อคุณใช้เศษส่วนจะเกิดขึ้น
Martin Thoma
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.