ทำคณิตศาสตร์ด้วยไม้ขีดไฟน้อยที่สุด


15

Meta-พื้นหลัง

นี่เป็นคำถามเกี่ยวกับ Puzzlingและปฏิกิริยาโต้ตอบแบบทันทีคือ "เอาล่ะใครสักคนจะแก้ปัญหาด้วยคอมพิวเตอร์" มีการถกเถียงกันว่าความซับซ้อนของโปรแกรมในการแก้ปัญหานี้จะต้องเป็นอย่างไร "โปรแกรมนี้ต้องซับซ้อนแค่ไหน" เป็นคำจำกัดความของค่อนข้างซับซ้อนดังนั้นบางที PPCG สามารถแก้ไขปัญหาได้?

พื้นหลัง

สมไม้ขีดไฟเป็นพื้นสมการทางคณิตศาสตร์ปกติ แต่ที่ตัวเลขและผู้ประกอบการมีการสร้างทางร่างกายโดยการวางไม้ขีดไฟลงบนโต๊ะ (คุณสมบัติที่เกี่ยวข้องหลักของไม้ขีดไฟที่นี่คือพวกมันค่อนข้างแข็งและมีความยาวคงที่บางครั้งคนใช้วัตถุอื่นแทนเช่นสำลีก้าน)

สำหรับความท้าทายนี้เราไม่จำเป็นต้องกำหนดกฎเฉพาะสำหรับการจัดเรียงไม้ขีดไฟ (เช่นเดียวกับความท้าทายที่เชื่อมโยง) แต่เราแค่แคร์ว่าจะต้องใช้ไม้ขีดไฟจำนวนเท่าไหร่ในการแทนค่านิพจน์ที่ประเมินเป็นจำนวนที่กำหนด

งาน

นี่คือตัวอักษรตัวเลขและตัวดำเนินการทางคณิตศาสตร์ที่คุณสามารถใช้ได้โดยแต่ละอันมีค่าใช้จ่ายเป็นไม้ขีดไฟ:

  • 0ราคา 6 ไม้ขีดไฟ
  • 1ราคา 2 matchsticks
  • 2ราคาทุน 5 ไม้ขีดไฟ
  • 3ราคาทุน 5 ไม้ขีดไฟ
  • 4ราคา 4 ไม้ขีดไฟ
  • 5ราคาทุน 5 ไม้ขีดไฟ
  • 6ราคา 6 ไม้ขีดไฟ
  • 7ราคาทุน 3 ไม้ขีดไฟ
  • 8ราคา 7 matchsticks
  • 9ราคา 6 ไม้ขีดไฟ
  • +ราคา 2 matchsticks
  • -ราคา 1 แท่งไม้ขีดไฟ
  • ×ราคา 2 matchsticks

(คุณอาจเป็นตัวแทน×เป็น*ในการส่งออกโปรแกรมของคุณหากคุณต้องการในการสั่งซื้อเพื่อหลีกเลี่ยงการต้องใช้ตัวอักษรที่ไม่ใช่ ASCII. ในการเข้ารหัสส่วนใหญ่×จะใช้เวลามากขึ้นไบต์กว่า*และดังนั้นผมจึงคิดว่าโปรแกรมส่วนใหญ่จะต้องการที่จะใช้ประโยชน์จากงานที่คั่งค้างนี้ .)

คุณต้องเขียนโปรแกรมที่ใช้จำนวนเต็มที่ไม่ใช่ค่าลบเป็นอินพุต (ผ่านวิธีการที่สมเหตุสมผล ) และสร้างนิพจน์ที่ประเมินเป็นจำนวนเต็มนั้นเป็นเอาต์พุต (อีกครั้งผ่านวิธีการที่สมเหตุสมผล) นอกจากนี้การแสดงออกจะต้องขับเคลื่อน: จะต้องมีอย่างน้อยหนึ่งผู้ประกอบการ+, หรือ- ×ในที่สุดนิพจน์ที่คุณส่งออกจะต้องเป็นค่าที่ถูกที่สุด (หรือเชื่อมโยงกับค่าที่ถูกที่สุด) ในแง่ของต้นทุนแท่งไม้ขีดไฟทั้งหมดในบรรดาเอาต์พุตทั้งหมดที่เป็นไปตามข้อกำหนด

ชี้แจง

  • คุณสามารถสร้างตัวเลขหลายหลักผ่านการแสดงผลหลายหลักในแถว (เช่น11-1ผลผลิตที่ถูกต้องในการผลิต10) เพียงเพื่อให้แม่นยำอย่างสมบูรณ์จำนวนผลลัพธ์จะถูกตีความเป็นทศนิยม การเรียงต่อกันแบบนี้ไม่ได้เป็นการดำเนินการที่ทำงานกับผลลัพธ์ระดับกลาง เฉพาะตัวเลขตัวอักษรที่ปรากฏในการแสดงออกเดิม
  • สำหรับจุดประสงค์ของการท้าทายนี้ +,, -และ×เป็นตัวดำเนินการมัด พวกเขาต้องการการโต้แย้งทางด้านซ้ายและทางขวา คุณยังไม่ได้รับอนุญาตให้ใช้พวกเขาอยู่ในตำแหน่งที่คำนำหน้าเหมือนหรือ+5-8
  • คุณไม่มีวงเล็บ (หรือวิธีอื่นในการควบคุมลำดับความสำคัญ) ที่มีอยู่ นิพจน์ประเมินตามกฎลำดับความสำคัญเริ่มต้นตามปกติ (การคูณเกิดขึ้นก่อนจากนั้นการบวกและการลบจะถูกประเมินจากซ้ายไปขวา)
  • คุณไม่มีสิทธิ์เข้าถึงตัวดำเนินการทางคณิตศาสตร์หรือค่าคงที่อื่นนอกเหนือจากที่ระบุไว้ข้างต้น "ความคิดด้านข้าง" มักจะเป็นที่ยอมรับในการแก้ปัญหาของ Puzzling แต่มันก็ไม่สมเหตุสมผลที่จะต้องใช้คอมพิวเตอร์ในการสร้างมันขึ้นมาเองและที่นี่ใน PPCG เราต้องการให้มันเป็นไปตามวัตถุประสงค์หรือไม่
  • ใช้กฎโอเวอร์โฟลว์จำนวนเต็มตามปกติ: วิธีแก้ปัญหาของคุณจะต้องสามารถทำงานกับจำนวนเต็มขนาดใหญ่ตามอำเภอใจในภาษาของคุณ (หรืออาจจะเป็นจริง) ในรูปแบบสมมุติซึ่งจำนวนเต็มทั้งหมดถูก จำกัด โดยค่าเริ่มต้น แต่ถ้าโปรแกรมของคุณล้มเหลว ไม่รองรับจำนวนเต็มที่มีขนาดใหญ่ซึ่งไม่ได้ทำให้โซลูชันไม่ถูกต้อง
  • หากคุณใช้ตัวเลขหรือตัวดำเนินการเดียวกันมากกว่าหนึ่งครั้งคุณจะต้องจ่ายค่าจับคู่ของมันทุกครั้งที่คุณใช้ (เพราะเห็นได้ชัดว่าคุณไม่สามารถนำมาใช้ซ้ำอีกครั้งในสถานที่สองแห่งบนโต๊ะ)
  • ไม่มีการ จำกัด เวลา วิธีการแก้ปัญหาแบบบังคับกำลังเป็นที่ยอมรับ (แม้ว่าคุณจะมีวิธีการแก้ปัญหาที่เร็วกว่ากำลังดุร้าย แต่คุณสามารถโพสต์ได้แม้จะนานกว่านั้นดูวิธีเปรียบเทียบทางเลือกที่น่าสนใจอยู่เสมอ)
  • แม้ว่าการเขียนคำอธิบายรหัสของคุณจะไม่จำเป็นแต่ก็น่าจะเป็นความคิดที่ดี มักยากที่จะอ่าน (โดยเฉพาะกับคนที่ไม่คุ้นเคยกับภาษาที่เขียน) และอาจเป็นการยากที่จะประเมิน (และลงคะแนนให้) การแก้ปัญหาถ้าคุณไม่เข้าใจวิธีการทำงาน

เงื่อนไขชัยชนะ

ในฐานะที่เป็นความท้าทายของคำตอบที่มีจำนวนไบต์น้อยกว่าจะถือว่าดีกว่า อย่างไรก็ตามตามปกติอย่าลังเลที่จะโพสต์คำตอบด้วยวิธีการที่แตกต่างกันหรือในภาษาที่เฉพาะเจาะจงแม้ว่าพวกเขาจะ verbose มากกว่าภาษาอื่น ๆ บางอย่าง; เป้าหมายของการเล่นกอล์ฟคือการดูว่าคุณสามารถเพิ่มประสิทธิภาพของโปรแกรมใดและการทำสิ่งต่าง ๆ ในลักษณะนี้ทำให้เรามีโปรแกรมที่เป็นไปได้ที่จะเพิ่มประสิทธิภาพ ดังนั้นอย่าท้อแท้หากมีคนส่งวิธีการแก้ปัญหาโดยใช้วิธีการที่แตกต่างกันโดยสิ้นเชิงหรือภาษาที่แตกต่างกันโดยสิ้นเชิงและได้รับคำตอบที่สั้นกว่ามาก มันอาจเป็นไปได้ว่าคำตอบของคุณนั้นได้รับการปรับปรุงให้ดีขึ้นและแสดงทักษะมากขึ้นและผู้ลงคะแนนใน PPCG มักจะชื่นชมสิ่งนั้น


Jeez, จำนวนสูงสุดที่เราต้องจัดการคืออะไร? ความพยายามในปัจจุบันของฉันจะไม่เกินกว่าที่ต้องการ ... อาจจะ 20 ใน TIO
Magic Octopus Urn

@Carococotputing: ในทางทฤษฎีสูงแต่ถ้าคุณไม่สามารถรับมากกว่า 20 ภายในเวลาที่เหมาะสมในการปฏิบัติก็ยอมรับได้ทั้งหมด

4
คุณมีกรณีทดสอบหรือไม่?
ลูกา

ฉันหวังว่านี่จะเป็นการดำเนินการครั้งเดียวแพร่กระจายไปกับการแข่งขันหลายรายการ การคูณเป็นปัญหาของตัวหาร แต่การบวกและการลบนั้นทำให้สิ่งต่าง ๆ ซับซ้อนยิ่งขึ้น ฉันมีโซลูชันที่ใช้งานได้ แต่ไม่ใช่สำหรับการบวกและการลบ ทำให้การทำงานนั้นสมบูรณ์แบบจะน่าเบื่อ
Magic Octopus Urn

@carusocomputing: คุณอาจสนใจความท้าทายนี้แล้ว ฉันสงสัยว่าความท้าทายในการคูณจะแตกต่างกันอย่างมากและจะต้องใช้เทคนิคการแก้ปัญหาที่แตกต่างกันเพื่อให้ได้คะแนนที่ดี

คำตอบ:


1

Python2, 1̶9̶8̶̶b̶y̶t̶e̶s̶ 182 ไบต์ขอบคุณ math_junkie

def f(n,c=dict(zip('0123456789+-*',map(int,'6255456376212'))),e=[(0,'')]):
 while 1:
    v=(m,s)=min(e);e.remove(v)
    try:
     if eval(s)==n:return s
    except:0
    e+=[(m+c[x],s+x)for x in c]

อัลกอริทึมนี้ไม่ทำอะไรเลยที่จะยกเว้นรุ่นนำหน้าของ+และ-แต่พวกเขาอาจจะเลวร้ายยิ่งกว่าหรือเท่ากับและปรากฏในภายหลังในการค้นหาคู่หูมัดของพวกเขา เนื่องจากใช้อาร์กิวเมนต์ของคำหลักอย่างไม่eแน่นอนจึงจะให้ผลลัพธ์ที่ไม่ถูกต้องหากเรียกหลายครั้งต่อเซสชัน เพื่อแก้ไขปัญหานี้ใช้แทนเพียงf(n, e=[(0,'')]) f(n)โปรดทราบว่าการเยื้องแบบเว้นวรรคสี่รายการแทนแท็บดังนั้นสิ่งนี้จะใช้ได้กับ Python 2 เท่านั้น

ฉันยังมีรุ่นที่ไม่ได้ปรับปรุงและเพิ่มประสิทธิภาพซึ่งทำงานได้อย่างรวดเร็วแม้เป็นจำนวนมาก:

from heapq import heappop, heappush

def f(n):
    digits = list('0123456789')
    ops =['+','-','*','']
    costs = dict(zip(digits + ops, [6,2,5,5,4,5,6,3,7,6,2,1,2,0]))
    expressions = [(costs[d], abs(n - int(d)), int(d), d) for d in digits[1:]]
    seen = set()
    while 1:
        cost, d, k, expression = heappop(expressions)
        if d == 0:
            return expression
        for op in ops:
            if op in '+-' and k in seen:
                continue
            for digit in digits:
                if op and digit == '0':
                    continue
                expression1 = expression + op + digit
                k1 = eval(expression1)
                d1 = abs(n - k1)
                if d1 == 0:
                    return expression1
                heappush(expressions, (cost+costs[op]+costs[digit], d1, k1, expression1))
        seen.add(k)

ผู้เยาว์บางคนแนะนำกอล์ฟ: TIO (182 bytes)
คณิตศาสตร์ junkie

1

PHP, 241 ไบต์

เวอร์ชั่นออนไลน์

function m($i){for(;$s<strlen($i);)$e+="6255456376"[$i[$s++]];return$e;}foreach($r=range(0,2*$a=$argv[1])as$v)foreach($r as$w)$x[$v+$w]["$v+$w"]=$x[$v*$w]["$v*$w"]=1+$x[$v-$w]["$v-$w"]=m("$v")+m("$w")+1;echo array_search(min($x[$a]),$x[$a]);

ชำรุด

function m($i){
    for(;$s<strlen($i);)$e+="6255456376"[$i[$s++]];return$e; #return the count of the matchstick for an integer
}

foreach($r=range(0,2*$a=$argv[1])as$v) # limit to an input to 300 in the online version
foreach($r as$w)
       $x[$v+$w]["$v+$w"]=  #fill the 2D array in the form [result][expression] = count matchsticks
       $x[$v*$w]["$v*$w"]=
       1+$x[$v-$w]["$v-$w"]=
       m("$v")+m("$w")+1;
echo $k=array_search(min($x[$a]),$x[$a]); # Output expression with a minium of matchsticks
echo"\t".$x[$a][$k]; #optional Output of the count of the matchsticks

วิธีที่มีประสิทธิภาพที่ดีขึ้นเล็กน้อย

function m($i){
for(;$s<strlen($i);)
$e+="6255456376"[$i[$s++]];return$e;} #return the count of the matchstick for an integer
foreach($r=range(0,2*$a=$argv[1])as$v)
foreach($r as$w){$c=m("$v")+m("$w")+1;
if($a==$v+$w)$x["$v+$w"]=1+$c; # fill array if value equal input
if($a==$v*$w)$x["$v*$w"]=1+$c;
if($a==$v-$w)$x["$v-$w"]=$c;}
echo $k=array_search(min($x),$x); # Output expression with a minium of matchsticks
    echo"\t".$x[$k]; #optional Output of the count of the matchsticks

สนับสนุนจำนวนเต็มลบ

รุ่นที่มีจำนวนเต็มลบ

function m($i){
    $e=$i<0?1:0; # raise count for negative integers
    for($s=0;$s<strlen($i);)$e+=[6,2,5,5,4,5,6,3,7,6][$i[$s++]];return$e; #return the count of the matchstick for an integer
}
$q=sqrt(abs($argv[1]));
$l=max(177,$q);
$j=range(-$l,$l); # for second loop for better performance
foreach($r=range(min(0,($a=$argv[1])-177),177+$a)as$v) 
foreach($j as$w){$c=m("$v")+m("$w")+1;  
    if($a==$v+$w)$x["$v+$w"]=1+$c; # fill array if value equal input
    if($a==$v*$w)$x["$v*$w"]=1+$c;
    if($a==$v-$w)$x["$v-$w"]=$c;
    if($a==$w-$v)$x["$w-$v"]=$c; # added for integers <0
}
echo $k=array_search(min($x),$x); # Output expression with a minium of matchsticks
echo"\t".$x[$k]; #optional Output of the count of the matchsticks

โอ้แล้วมันก็ใช้ได้กับจำนวนลบด้วยเช่นกัน!
Magic Octopus Urn

@carusocomputing ไม่จริงอาจเป็นไปได้ว่ามีวิธีแก้ปัญหาด้วยไม้ขีดไฟน้อยกว่าทำให้เกิดการลบตัวเลขโดยการลบเท่านั้น ในกรณีนี้คุณควรตรวจสอบค่าสัมบูรณ์ด้วยและเพิ่มหนึ่ง
JörgHülsermann

ฉันไม่คิดว่าตัวอักษร 333 จะยอมรับได้ที่นี่แม้ว่าคุณจะสามารถแก้ไขได้ด้วยการทำให้ฟังก์ชั่นของอินพุต (โปรแกรมอาจทำงานช้าลงมากดังนั้นคุณสามารถเก็บรุ่น hardcoded สำหรับการทดสอบได้)

1
@ ais523 เสร็จแล้ว 333 ถูกแทนที่ด้วยอินพุต 2 *
JörgHülsermann

1
$e+="6255456376"[$i[$s++]];คุณสามารถสตริงดัชนี:
จัดการ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.