Làm toán với các que diêm tối thiểu


15

Siêu nền

Điều này được đặt ra như một câu hỏi trên Puzzling , và phản ứng tức thì là "tốt, ai đó sẽ giải quyết nó bằng máy tính". Có một cuộc tranh luận về mức độ phức tạp của một chương trình để giải quyết vấn đề này. Chà, "chương trình này phải phức tạp đến mức nào" gần như là định nghĩa của , vậy có lẽ PPCG có thể giải quyết vấn đề này không?

Lý lịch

Một phương trình que diêm về cơ bản là một phương trình toán học bình thường, nhưng trong đó các chữ số và toán tử được xây dựng vật lý bằng cách đặt que diêm lên bàn. (Đặc điểm chính có liên quan của que diêm ở đây là chúng khá cứng và có độ dài không đổi; đôi khi người ta sử dụng các vật thể khác thay thế, chẳng hạn như tăm bông.)

Đối với thử thách này, chúng tôi không cần xác định các quy tắc cụ thể về cách sắp xếp các que diêm (giống như thử thách được liên kết); thay vào đó, chúng tôi chỉ quan tâm đến việc có bao nhiêu que diêm mà chúng tôi sẽ cần để biểu thị một biểu thức ước lượng cho một số đã cho.

Nhiệm vụ

Dưới đây là bảng chữ cái gồm các chữ số và toán tử toán học mà bạn có thể sử dụng, mỗi cái có một chi phí bằng que diêm:

  • 0, giá 6 que diêm
  • 1, tốn 2 que diêm
  • 2, giá 5 que diêm
  • 3, giá 5 que diêm
  • 4, giá 4 que diêm
  • 5, giá 5 que diêm
  • 6, giá 6 que diêm
  • 7, tốn 3 que diêm
  • 8, giá 7 que diêm
  • 9, giá 6 que diêm
  • +, tốn 2 que diêm
  • -, tốn 1 que diêm
  • ×, tốn 2 que diêm

(Bạn có thể đại diện ×như *trong đầu ra của chương trình của bạn nếu bạn muốn, để tránh cần phải sử dụng các ký tự ASCII. Trong hầu hết các mã hóa, ×chiếm hơn byte hơn *, và vì vậy tôi tưởng tượng rằng hầu hết các chương trình sẽ muốn tận dụng lợi thế của sự trôi nổi này .)

Bạn cần viết một chương trình lấy số nguyên không âm làm đầu vào (thông qua bất kỳ phương tiện hợp lý nào ) và tạo một biểu thức ước lượng cho số nguyên đó làm đầu ra (một lần nữa thông qua bất kỳ phương tiện hợp lý nào). Ngoài ra, khái niệm phải không tầm thường: nó phải chứa ít nhất một nhà điều hành +, -hoặc ×. Cuối cùng, biểu thức bạn xuất ra phải rẻ nhất (hoặc được gắn với giá rẻ nhất) về tổng chi phí que diêm, trong số tất cả các đầu ra tuân thủ theo đặc điểm kỹ thuật.

Làm rõ

  • Bạn có thể hình thành các số có nhiều chữ số thông qua việc xuất nhiều chữ số liên tiếp (ví dụ: 11-1là đầu ra hợp lệ để sản xuất 10). Chỉ cần hoàn toàn chính xác, số kết quả được giải thích bằng số thập phân. Kiểu kết nối này không phải là một hoạt động hoạt động trên các kết quả trung gian; chỉ trên các chữ số xuất hiện trong biểu thức gốc.
  • Với mục đích của thử thách này. +, -×là các toán tử infix; họ cần một cuộc tranh cãi bên trái và bên phải của họ. Bạn không được phép sử dụng chúng ở vị trí tiền tố như +5hoặc -8.
  • Bạn không có dấu ngoặc đơn (hoặc bất kỳ cách nào khác để kiểm soát quyền ưu tiên) có sẵn. Biểu thức đánh giá theo các quy tắc ưu tiên mặc định điển hình (phép nhân xảy ra trước, sau đó các phép cộng và phép trừ được đánh giá từ trái sang phải).
  • Bạn không có quyền truy cập vào bất kỳ toán tử hoặc hằng số toán học nào ngoài các toán tử được liệt kê ở trên; Các giải pháp "tư duy bên" thường được chấp nhận tại Puzzling, nhưng sẽ không có ý nghĩa khi yêu cầu một máy tính tự tìm ra chúng, và ở đây trên PPCG, chúng tôi muốn nó là khách quan cho dù giải pháp đó có đúng hay không.
  • Áp dụng quy tắc tràn số nguyên thông thường: giải pháp của bạn phải có khả năng hoạt động cho các số nguyên lớn tùy ý trong phiên bản giả định (hoặc có thể có thật) của ngôn ngữ của bạn trong đó tất cả các số nguyên không bị ràng buộc theo mặc định, nhưng nếu chương trình của bạn không thực hiện do thực hiện do thực hiện không hỗ trợ số nguyên lớn, điều đó không làm mất hiệu lực giải pháp.
  • Nếu bạn sử dụng cùng một chữ số hoặc toán tử nhiều lần, bạn phải trả chi phí cho que diêm của nó mỗi lần bạn sử dụng (vì rõ ràng, bạn không thể sử dụng lại cùng một que diêm vật lý ở hai vị trí khác nhau trên bàn).
  • Không có giới hạn thời gian; giải pháp vũ phu được chấp nhận. (Mặc dù nếu bạn có một giải pháp nhanh hơn sức mạnh vũ phu, hãy thoải mái đăng nó ngay cả khi nó dài hơn; xem cách tiếp cận thay thế so sánh luôn thú vị.)
  • Mặc dù viết một lời giải thích về mã của bạn là không bao giờ được yêu cầu , nó có thể là một ý tưởng tốt; giải pháp thường rất khó đọc (đặc biệt là với những người không quen thuộc với ngôn ngữ họ viết) và có thể khó đánh giá (và do đó bỏ phiếu) một giải pháp trừ khi bạn hiểu cách thức hoạt động của nó.

Điều kiện chiến thắng

Là một thử thách , câu trả lời có ít byte hơn được coi là tốt hơn. Tuy nhiên, như thường lệ, vui lòng đăng câu trả lời với các cách tiếp cận khác nhau hoặc bằng các ngôn ngữ cụ thể ngay cả khi chúng dài dòng hơn các ngôn ngữ khác; Mục tiêu của golf là thực sự để xem bạn có thể tối ưu hóa một chương trình cụ thể bao xa và thực hiện mọi thứ theo cách này mang lại cho chúng tôi rất nhiều chương trình tiềm năng để tối ưu hóa. Vì vậy, đừng nản lòng nếu ai đó gửi giải pháp bằng cách sử dụng một cách tiếp cận hoàn toàn khác, hoặc một ngôn ngữ hoàn toàn khác và nhận được câu trả lời ngắn hơn nhiều; có thể là câu trả lời của bạn được tối ưu hóa tốt hơn và thể hiện nhiều kỹ năng hơn, và những người bỏ phiếu trên PPCG thường đánh giá cao điều đó.


Jeez, con số cao nhất chúng ta cần xử lý là gì? Nỗ lực hiện tại của tôi sẽ không vượt quá như ... có thể là 20 trên TIO.
Bạch tuộc ma thuật Urn

@carusocomputing: Về lý thuyết rất cao , nhưng nếu bạn không thể vượt quá 20 trong một thời gian hợp lý trong thực tế, điều đó hoàn toàn chấp nhận được.

4
Bạn có bất kỳ trường hợp thử nghiệm?
Lu-ca

Tôi thực sự muốn đây là một hoạt động duy nhất, trải rộng trên nhiều cuộc thi. Phép nhân là một vấn đề chia, nhưng thêm vào và trừ thực sự làm phức tạp mọi thứ. Tôi có một giải pháp hiệu quả, nhưng không phải cho phép cộng và trừ; làm cho công việc đó hoàn hảo sẽ tẻ nhạt
Bạch tuộc ma thuật Urn

@carusocomputing: Sau đó, bạn có thể quan tâm đến thử thách này . Tôi nghi ngờ thử thách với phép nhân chỉ khác biệt đáng kể và sẽ yêu cầu các kỹ thuật giải pháp khá khác nhau để có được điểm cao.

Câu trả lời:


1

Python2, 1̶9̶8̶ b̶y̶t̶e̶s̶ 182 byte nhờ 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]

Thuật toán này không có gì để loại trừ các phiên bản tiền tố của +-, nhưng chúng sẽ tệ hơn, hoặc bằng và xuất hiện sau đó trong tìm kiếm, đối tác trung gian của chúng. Bởi vì nó sử dụng đối số từ khóa một cách eđột biến, nó sẽ cho kết quả không hợp lệ nếu được gọi nhiều lần trong mỗi phiên. Để khắc phục điều này, sử dụng f(n, e=[(0,'')])thay vì chỉ f(n). Lưu ý rằng các thụt lề bốn khoảng cách đại diện cho các tab, vì vậy điều này sẽ chỉ hoạt động với Python 2.

Tôi cũng có một phiên bản không được tối ưu hóa và tối ưu hóa, chạy rất nhanh ngay cả với số lượng khá lớn:

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)

Một số golf được đề xuất nhỏ: TIO (182 byte)
nghiện toán học

1

PHP, 241 byte

Phiên bản trực tuyến

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]);

Phá vỡ

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

Cách với hiệu suất tốt hơn một chút

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

Hỗ trợ số nguyên âm

Phiên bản có số nguyên âm

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

Oh snap, điều này hoạt động trên các số âm quá!
Bạch tuộc ma thuật Urn

@carusocomputing không thực sự có thể là một giải pháp tồn tại với ít que diêm khiến số âm chỉ được thêm vào bằng phép trừ. trong trường hợp này, bạn cũng nên kiểm tra giá trị tuyệt đối và thêm một giá trị
Jörg Hülsermann

Tôi không nghĩ rằng chữ 333 sẽ được chấp nhận ở đây, mặc dù bạn có thể sửa nó bằng cách biến nó thành một số chức năng của đầu vào. (Chương trình có thể chạy chậm hơn nhiều, vì vậy bạn có thể giữ phiên bản được mã hóa cứng để thử nghiệm.)

1
@ ais523 thực hiện 333 được thay thế bằng đầu vào 2 *
Jörg Hülsermann

1
Bạn có thể lập chỉ mục chuỗi : $e+="6255456376"[$i[$s++]];.
thao tác
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.