Tám đồng xu cho vua công bằng


22

Đây là một "bản sao" của một câu đố khác, Tám đồng xu cho vị vua công bằng trên Puzzling.SE.

Bạn có thể đọc các câu đố trên cho nền. Các chi tiết về câu đố này như sau.

Một bộ gồm 8 loại tiền có giá trị khác nhau được tạo ra, nhà vua muốn bạn tìm ra N tối đa sao cho bất kỳ số giá nào từ 0 đến N có thể được thanh toán với sự kết hợp không quá 8 đồng và không tính phí.

Ví dụ: (lấy từ câu trả lời của Glorfindel). Nếu một tập hợp các đồng tiền có giá trị 1, 2, 5, 13, 34, 89, 233, 610 được đưa ra, chương trình của bạn sẽ xuất ra 1596, bởi vì mọi số từ 0 đến 1596 (đã bao gồm) có thể được biểu thị bằng tổng không quá hơn 8 số từ danh sách đã cho (số có thể lặp lại), trong khi 1597 không thể được biểu diễn theo cách đó.

Theo cách toán học, nếu đầu vào là tập S bao gồm 8 số nguyên dương, thì đầu ra N mong muốn thỏa mãn rằng với bất kỳ số n nào trong khoảng từ 0 đến N, tồn tại x1, x2, x3, ..., x8 sao cho

x1+x2+...+x8=nandx1,x2,...,x8{0}S

Mục tiêu của bạn là viết một chương trình, hàm hoặc đoạn trích lấy 8 số làm đầu vào và xuất N tối đa như mô tả ở trên.

Quy tắc:

  • I / O linh hoạt được phép, vì vậy chương trình của bạn có thể lấy đầu vào dưới mọi hình thức phù hợp nhất. Bạn có thể cho rằng các số đầu vào được sắp xếp theo cách phù hợp nhất với chương trình của bạn.
    • Vui lòng nêu nó trong câu trả lời của bạn nếu chương trình của bạn phụ thuộc vào thứ tự đầu vào
  • Đầu vào là một bộ gồm 8 số nguyên dương khác nhau (không có số không). Đầu ra là một số nguyên không âm.
    • Trong trường hợp không có 1 trong tập đầu vào, chương trình của bạn sẽ xuất 0 vì bất kỳ số nào từ 0 đến 0 đều thỏa mãn yêu cầu.
    • Trong trường hợp đầu vào không hợp lệ (bộ chứa số 0, số âm hoặc số trùng lặp), chương trình của bạn có thể làm bất cứ điều gì.
  • Sơ hở tiêu chuẩn bị cấm.
  • Chương trình của bạn sẽ chạy trong vòng vài phút trên một máy tính hiện đại.

Các trường hợp thử nghiệm (chủ yếu được lấy từ các câu trả lời dưới câu hỏi được liên kết trên Puzzling):

[1, 2, 3, 4, 5, 6, 7, 8] => 64
[2, 3, 4, 5, 6, 7, 8, 9] => 0
[1, 3, 4, 5, 6, 7, 8, 9] => 72
[1, 2, 5, 13, 34, 89, 233, 610] => 1596
[1, 5, 16, 51, 130, 332, 471, 1082] => 2721
[1, 6, 20, 75, 175, 474, 756, 785] => 3356

Đây là một , vì vậy chương trình hoặc đoạn ngắn nhất trong mỗi ngôn ngữ sẽ thắng!


1
Câu đố hay, nhưng cá nhân tôi nghĩ rằng một số trường hợp thử nghiệm nữa sẽ hữu ích để kiểm tra bài nộp của chúng tôi.
Ông Xcoder

Sẽ không tốt hơn để làm cho kích thước đầu vào một tham số? Phương pháp tiếp cận lực lượng vũ phu sẽ đấu tranh với 8
Luis Mendo

1
@iBug Sau đó, quy tắc thông thường là một cái gì đó như "đệ trình sẽ chạy trong vòng một phút trong một máy tính hiện đại". Nó mờ, nhưng thường đủ tốt, bởi vì sự khác biệt giữa lực lượng vũ phu và cách tiếp cận hiệu quả là rất lớn
Luis Mendo

1
Lực lượng vũ phu vẫn có thể với giới hạn thời gian của bạn là "một vài phút". Một phiên bản sửa đổi một chút của câu trả lời của tôi chạy trường hợp thử nghiệm cuối cùng trong 1m20 trên máy tính xách tay 7 tuổi của tôi.
nimi

1
@Arnauld Làm rõ
iBug

Câu trả lời:



9

Thạch , 12 byte

œċⱮ8Ẏ§ṢQJƑƤS

Hãy thử trực tuyến!

Mất trung bình ~ 3,7 giây để chạy tất cả các trường hợp thử nghiệm trên TIO trên điện thoại của tôi, thật ngạc nhiên là nó khá nhanh.

Giải trình

œċⱮ8Ẏ§ṢQJƑƤS     Monadic link / Full program.
  Ɱ8             Promote 8 to [1 ... 8] and for each value k:
œċ                    Generate all combinations of k elements from the list.
    Ẏ§           Tighten, then sum. Flatten to a 2D list then sum each.
      ṢQ         Sort the result and remove equal entries.
        JƑƤ      For each prefix of this list, return 1 if it is equal to its length range, 0 otherwise.
           S     Finally, sum the result (counts the 1's which is equivalent to what is being asked).

7

Haskell, 56 50 byte

g c=[x|x<-[1..],all((/=x).sum)$mapM(0:)$c<$c]!!0-1

Hãy thử trực tuyến!

Một cách tiếp cận vũ phu. Thêm 0vào danh sách các đồng tiền và thử tất cả các kết hợp của 8 lượt chọn. Tìm số đầu tiên nkhông bằng tổng của bất kỳ số chọn nào và trả về n-1.

Mất khoảng 5m30 cho [1, 2, 5, 13, 34, 89, 233, 610]phần cứng máy tính xách tay 7 tuổi của tôi.

Chỉnh sửa: -6 byte nhờ @ janrjan Johansen

Một phiên bản thậm chí còn ngắn hơn (-2 byte, một lần nữa nhờ @ rjan Johansen) là

Haskell, 48 byte

g c=[x|x<-[1..],all((/=x).sum)$mapM(:0:c)c]!!0-1

nhưng nó sử dụng nhiều bộ nhớ hơn và chạy vào phân trang nặng trên máy của tôi và không hoàn thành "trong vòng vài phút".


1
Bạn có thể sử dụng mapM(0:)$c<$c. (Trên thực tế mapM(:0:c)cnên hoạt động, nhưng hết thời gian trên TIO cho trường hợp thử nghiệm đã cho.)
Ørjan Johansen

4

Thạch , 9 byte

Żœċ8§ḟ’$Ṃ

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

Żœċ8§ḟ’$Ṃ  Main link. Argument: A (array)

Ż          Prepend a 0 to A.
 œċ8       Take all combinations of length 8, with repetitions.
    §      Take the sum of each combination.
       $   Combine the two links to the left into a monadic chain.
      ’      Decrement all sums.
     ḟ       Filterfalse; keep only sums that do not appear in the decremented sums.
        Ṃ  Take the minimum.

2
Żṗ8§ḟ’$Ṃtiết kiệm một byte, nhưng tôi không chắc nếu 8,5 phút được tính là một vài .
Dennis


4

JavaScript (ES6),  100 88 80  76 byte

Đây thực chất là một tìm kiếm vũ phu, nhưng được tăng cường với việc cắt tỉa để tăng tốc nó. Thời gian thực hiện trung bình cho các trường hợp thử nghiệm là gần 1 giây trên TIO.

Giả sử rằng mảng đầu vào được sắp xếp từ cao nhất đến thấp nhất.

a=>[...Array(a[0]*9)].findIndex(g=(i=8,s)=>s*i>0?a.every(x=>g(i-1,s-x)):s)-1

Hãy thử trực tuyến!

Đã bình luận

a =>                      // a[] = input array
  [...Array(a[0] * 9)]    // create an array of 9 * max(a) entries
  .findIndex(             // find the position of the first truthy result
    g = (i = 8, s) =>     // g = recursive function taking a counter i, initialized to 8
                          //     and a sum s, initialized to the position in the above array
      s * i > 0 ?         //   if s is positive and i is not equal to 0:
        a.every(x =>      //     for each value x in a[]:
          g(i - 1, s - x) //       do a recursive call with i - 1 and s - x
        )                 //     end of every()
      :                   //   else:
        s                 //     yield s (s = 0 means success and makes findIndex go on)
  ) - 1                   // end of findIndex(); decrement the result


3

Pari / GP , 57 byte

a->n=-1;while(polcoeff((1+sum(i=1,8,x^a[i]))^8,n++),);n-1

Hãy thử trực tuyến!


Đây có phải là sử dụng chức năng tạo?
don sáng

1
@donbright Vâng.
alephalpha

1
đó là tuyệt vời .. một trong số ít câu trả lời không phải là vũ phu buộc giải pháp. Rất nhiều ngôn ngữ có thể không được xây dựng trong các tính năng biểu tượng đa thức. Pari GP rất tuyệt.
don sáng

2

Python 2 , 125 115 111 byte

lambda c:sum(i==j for i,j in enumerate(sorted(set(map(sum,product([0]+c,repeat=8))))))-1
from itertools import*

Hãy thử trực tuyến!

Mong đợi một danh sách các số nguyên làm đầu vào.

Giải trình:

# an anonymous function
lambda c:
                                                          # get all length-8 combinations of values, from (0,0,0,0,0,0,0,0) to (8,8,8,8,8,8,8,8)
                                                          # zero is added to ensure that combinations of fewer than 8 coins are represented Ex:(1,0,0,0,0,0,0,0)
                                                          product([0]+c,repeat=8)
                                                  # for each combination, sum the values
                                                  map(sum,.......................)
                                       # get unique values, then sort them smallest to largest
                                       sorted(set(................................))
             # for each index, value pair, return if the index is equal to the value
             i==j for i,j in enumerate(.............................................)
         # in Python arithmetic, False is 0 and True is 1. So, count how many items match their index.
         # Since zero was added to the list, there will always be one extra match (0==0). So offset by one.
         sum(........................................................................)-1
from itertools import*

2

Perl6, 65 63 41 byte ( 39 37 ký tự)

{@_=(0,|@_)X+(0,|@_)for ^3;($_ if $_==$++for @_.sort.unique)-1}

Hãy thử trực tuyến!

Đây là một khối ẩn danh được truyền dữ liệu của nó dưới dạng một mảng. Đây (0,|@_)là một cách nhanh chóng để thêm 0vào @_và mặc dù đã hoàn thành hai lần, nhưng nó vẫn ngắn hơn một chút so với thời gian @_.push: 0;sau đó sẽ cần khoảng trắng _. Đây là một cách tiếp cận mạnh mẽ, phù hợp với thực tế là 8 kết hợp. Sau khi thêm chéo, một danh sách ẩn danh được tạo cho các giá trị tuần tự. Với các toán tử toán học, các danh sách ước tính theo độ dài của chúng, do đó -1 kéo theo nhiệm vụ kép: chiếm 0 và ép buộc vào Int.

Điều này có thể mất thời gian ngọt ngào của nó, nhưng bằng cách thay đổi một hoặc cả hai (0,|@_)để (0,|@_.unique)trước khi là người đầu tiên fornó có thể được tăng tốc đáng kể. Điều đó cộng thêm +7 (thời gian chạy <60 giây) hoặc +14 (thời gian chạy <10 giây) vào điểm số nếu bạn cảm thấy đầu tiên quá chậm (tôi đã làm điều này cho mã được liên kết để tránh thời gian chờ sau 60 giây).

Chỉnh sửa: Tham gia vào các bình luận đã cải thiện nó (cùng ý tưởng, thêm chéo, sau đó trả lại kết quả liên tiếp cuối cùng) thành 39 ký tự đáng kinh ngạc (41 byte):

{(@_=@_ X+0,|@_)xx 3;first *+1@_,^∞}

Hãy thử trực tuyến!

Việc lập bảng cuối cùng không cần 0, tiết kiệm một vài byte bằng cách chỉ cần thêm 0 trong một lần. Bắt xx 3chước vòng lặp for (vẫn là pho mát trên đồng xu là sức mạnh của 2). Các firstphụ trả về số đầu tiên trong danh sách vô hạn 0..*( ^Infcó thể quá, nhưng không tiết kiệm không gian) mà +1không phải là một thành viên của danh sách bổ sung chéo. Giống như của tôi, nó chậm, vì vậy hãy thêm +7 cho uniquelần đầu tiên bằng nếu bạn cảm thấy nó quá chậm so với hướng dẫn.


1
48 byte . Về mặt kỹ thuật, điều uniquenày là không cần thiết, nhưng nó tăng tốc rất nhiều
Jo King

@JoKing tốt, tôi không biết tại sao tôi không nghĩ về việc sử dụng xx. Tôi biết rằng phải có một cách để lập bảng cuối cùng theo cách ngắn hơn nhiều bằng cách sử dụng các hàm thiết lập, nhưng bộ não của tôi không hoạt động.
user0721090601 28/12/18

Các xx 1nênxx 3
Jo vua

@JoKing cố định. Ngoài ra tôi nhận ra hai ký tự (nhưng không có byte) có thể được lưu bằng cách sử dụng^∞
user0721090601

Trên thực tế, bạn có thể lưu một số byte bằng (1...*∉@_)-1thay vì sử dụng first, (mà tôi nhận ra là cùng một phương pháp tôi đã sử dụng ở đây )
Jo King

1

JavaScript (Node.js) , 171 145 115 byte

f=(s,n=3)=>n?f(s=new Set(a=[0,...s]),n-1,a.map(m=>a.map(n=>s.add(m+n)))):Math.min(...[...s].filter(m=>!s.has(m+1)))

Hãy thử trực tuyến! Cổng câu trả lời Python 3 của @ Mark. 108 byte trong Firefox 30-57:

f=(s,n=3)=>n?f(new Set((for(n of s=[0,...s])for(m of s)n+m)),n-1):Math.min(...[...s].filter(m=>!s.has(m+1)))

1

Ngôn ngữ Wolfram (Mathicala) , 46 byte

0//.x_/;Min[Tr/@FrobeniusSolve[#,x+1]]<9:>x+1&

Hãy thử trực tuyến!

Phương pháp tiếp cận mạnh mẽ: kiểm tra các số nguyên đếm ngược lên cho đến khi đạt đến giá trị không thể thanh toán bằng 8 xu. Rất, rất chậm (hết ba lần), nhưng tôi khá chắc chắn điều kiện này là chính xác.


0

Sạch , 161 byte

import StdEnv,Data.List
$l=:[1:_]#k=sort(nub(map sum(iter 8(concatMap(\[h:t]=[[e,h:t]\\e<-[0:l]|e>=h]))[[0]])))
=length(takeWhile((>=)1)(zipWith(-)(tl k)k))
$_=0

Hãy thử trực tuyến!

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.