Kode Nugget

18

Kode Nugget

Ini adalah situasi hipotetis di mana hari Jumat malam, dan Anda telah mengundang teman bermain golf yang biasa untuk berpartisipasi dalam hobi favorit Anda: golf kode. Namun, karena ini adalah tugas yang menguras otak, Anda perlu mengambil beberapa makanan otak untuk grup sehingga Anda dapat bermain golf sebanyak mungkin dari kode Anda.

Sekarang, camilan favorit semua orang adalah chicken nugget, tetapi ada masalah: Tidak ada satu pun dari mereka yang memenuhi kebutuhan semua orang. Jadi, karena Anda sudah berada dalam suasana golf, Anda memutuskan untuk membuat program yang menentukan paket apa yang harus Anda beli untuk dapat memenuhi kebutuhan Nugget semua orang.

Ukuran paket nugget ayam ada di semua tempat, dan tergantung di mana Anda tinggal di dunia, ukuran standar juga berubah. Namun, [tempat terdekat yang menyediakan nugget] terdekat menyediakan paket nugget ukuran berikut:

4, 6, 9, 10, 20, 40

Sekarang Anda mungkin memperhatikan bahwa Anda tidak dapat memesan kombinasi nugget tertentu. Misalnya, 11nugget tidak dimungkinkan, karena tidak ada kombinasi yang sama 11persis. Namun, Anda dapat membuatnya 43dengan mendapatkan 1 bungkus 20, 1 bungkus 10, 1 bungkus 9dan 1 bungkus 4,

20 + 10 + 9 + 4 = 43 (597)

di mana 597setiap istilah kuadrat dan ditambahkan bersama-sama (petunjuk: solusi optimal memiliki ini sebagai nilai tertinggi) . Tentu saja ada cara lain untuk membuatnya 43, tetapi seperti yang Anda tahu, semakin banyak nugget per bungkus, semakin murah nugget per paket. Jadi, Anda ingin membeli secara ideal jumlah paket paling sedikit dan dalam jumlah terbesar untuk meminimalkan biaya Anda.

Tugas

Anda harus membuat program atau fungsi yang mengambil daftar bilangan bulat yang sesuai dengan kebutuhan setiap orang. Anda kemudian harus menghitung dan mencetak pesanan α paling efisien untuk membeli nugget ayam. Urutan α yang paling hemat biaya adalah kombinasi dimana jumlah kuadrat dari setiap kuantitas adalah yang tertinggi. Jika sama sekali tidak ada cara untuk membeli nugget dengan sempurna, Anda harus mencetak nilai palsu seperti0 , False, Impossible!, atau apa pun yang tersedia dalam bahasa Anda.

Contoh I / O:

[2 7 12 4 15 3] => [20 10 9 4]
     1, 1, 2, 1 => False
  6 5 5 5 5 5 9 => 40
      [6, 4, 9] => 9 10
              1 => 0
            199 => 40, 40, 40, 40, 20, 10, 9
              2 => Impossible!

Sini adalah daftar solusi ideal untuk 400 yang pertama. Perhatikan ini tidak diformat seperti yang saya harapkan dari Anda, masing tuple- masing ada dalam formulir (N lots of M).

Aturan

  1. Tidak ada celah standar.
  2. Tidak menggunakan fungsi bawaan yang melakukan semua atau sebagian besar tugas, seperti FrobeniusSolvedi Mathematica.

α - Untuk mengklarifikasi ini dengan sebuah contoh, Anda juga dapat membuat 43 dengan melakukan 4 + 6 + 6 + 9 + 9 + 9 = 43 (319), tetapi ini tidak akan optimal, dan dengan demikian output yang salah, karena jumlah kuadrat kurang dari kombinasi yang saya catat dalam pendahuluan. Pada dasarnya, jumlah kuadrat yang lebih tinggi = biaya lebih rendah = paling hemat biaya.

Kade
sumber
Apakah ada batasan waktu / memori?
Dennis
@ Dennis Tidak ada batas waktu atau memori.
Kade
4
Ini sebenarnya hari Kamis.
mbomb007
4
@ mbomb007 Pengamatan cerdas: P Saya telah menyesuaikan intro.
Kade
2
Saya PERLU untuk menggunakan teorema ayam mcnugget entah bagaimana ...
Stretch Maniac

Jawaban:

7

Pyth, 26 25 byte

e+Zo.aNf!-TCM"  
("./sQ

Perhatikan bahwa ada beberapa karakter yang tidak diinginkan. Cobalah online: Demonstrasi . Ini cukup lambat (tapi tidak selambat solusi 26 byte saya).

Penjelasan:

                          implicit: Q = input list
                     sQ   sum(Q)
                   ./     generate all integer partitions
       f                  filter for partitions T, which satisfy:
             "   ("          string containing chars with the ASCII-values of 4,6,9,10,20,40
           CM                convert each char to the ASCII-value
         -T                  remove this numbers from T
        !                    and check, if the resulting list is empty
    o                      order the remaining subsets N by:
     .aN                      the vector length of N (sqrt of sum of squares)
  +Z                       insert 0 at the beginning
 e                         print the last element

Pyth, 32 byte

e+Zo.aNfqsTsQysm*]d/sQdCM"  
(

Perhatikan bahwa ada beberapa karakter yang tidak diinginkan. Cobalah online: Peragaan Versi ini jauh lebih cepat. Ia menemukan solusi untuk input [6,7,8]dalam waktu sekitar satu detik dan solusi untuk input [30]dalam waktu sekitar 90 detik.

Penjelasan:

                                 implicit: Q = input list
                          "...(  the string containing chars with the ASCII-values of 4,6,9,10,20,40
                        CM       convert each char to the ASCII-value
                m                map each number d to:
                  ]d                create the list [d]
                 *  /sQd            and repeat it sum(Q)/d times
               s                 unfold
              y                  generate all subsets
        f                        filter for subsets T, which satisfy:
         qsTsQ                      sum(Q) == sum(T)
    o                            order the remaining subsets N by:
     .aN                            the vector length of N (sqrt of sum of squares)
  +Z                             insert 0 at the beginning
 e                               print the last element
Jakube
sumber
Mengapa dengan sqrt dari jumlah kuadrat, bukan hanya jumlah?
mbomb007
1
@ mbomb007 Karena itu tidak masalah. Jika a> b, dari sqrt (a)> sqrt (b) dan sebaliknya. Dan menggunakan .ametode ini lebih pendek dari mengkuadratkan dan menjumlahkan s^R2.
Jakube
5

Perl, 175 153

sub f{my$n=$_[0];if(!$n){return 1;}foreach$o(40,20,9,10,6,4){if($n>=$o&&f($n-$o)){print"$o ";return 1;}}return 0;}$n+=$_ for@ARGV;if(!f($n)){print":(";}

Mengambil input dari argumen program. Mencetak :( jika tidak dapat menemukan solusi yang sempurna.

Kode Tidak Terkunci:

sub f
{
    my $n = $_[0];
    if(!$n)
    {
        return 1;
    }
    foreach $o(40,20,9,10,6,4)
    {
        if($n>=$o&&f($n-$o))
        {
            print "$o ";
            return 1;
        }
    }
    return 0;
}

$n += $_ for @ARGV;
if(!f($n))
{
    print ":(";
}

PS: Ini mungkin entri pertama yang tidak membutuhkan waktu 10 menit 1 2;)

Lihat disini.

Thomas Oltmann
sumber
Selamat atas apa yang tampaknya menjadi program tercepat sejauh ini! Mungkin lebih cepat daripada program referensi saya juga: P Saya telah menambahkan tautan ideone di bagian bawah posting Anda sehingga orang dapat melihat hasilnya.
Kade
Kode Anda dapat menghasilkan output yang salah. Input 18harus dicetak 9 9, bukan 4 4 10.
Dennis
Ada juga output salah lainnya. Jika saya tidak salah, Anda dapat memperbaikinya dengan menukar urutan 9dan 10.
Dennis
@ Dennis Terima kasih, perbaiki!
Thomas Oltmann
3

CJam, 45 29 28 byte

q~:+_[40K9A6Z)U]m*_::+@#=0-p

Perhatikan bahwa pendekatan ini sangat lambat dan intensif memori.

Cobalah online di juru bahasa CJam .

Ini dapat dipercepat secara signifikan dengan biaya 5 byte:

q~:+_40/4+[40K9A6Z)U]m*_::+@#=0-p

Kompleksitas masih eksponensial dalam jumlah input, tetapi ini harus menangani kasus uji hingga 159 dengan penerjemah online dan hingga 199 dengan penerjemah Java dalam beberapa detik.

Cobalah online di juru bahasa CJam .

Ide

Pembelian yang optimal (jumlah maksimal dari kotak) adalah pembelian yang sah (jumlah yang benar nugget) yang memiliki banyak 40 's mungkin, maka sebanyak 20 ' s mungkin, maka sebanyak 9 's mungkin (misalnya, 9 9adalah lebih disukai daripada 10 4 4) dan sebagainya untuk 10 , 6 dan 4 .

Dalam pendekatan ini, kami menghasilkan produk Cartesian dari N salinan array [40 20 9 10 6 4 0] , di mana N adalah jumlah nugget yang diinginkan. N adalah batas atas (buruk) untuk jumlah pembelian yang harus kita lakukan. Dalam versi kode yang dipercepat, kami menggunakan N / 40 + 4 sebagai gantinya.

Karena cara susunannya diatur, produk Cartesian akan mulai dengan vektor [40 ... 40] dan berakhir dengan vektor [0 ... 0] . Kami menghitung indeks vektor pertama yang memiliki jumlah yang benar (yang juga akan memiliki jumlah kuadrat optimal), mengambil elemen array yang sesuai, menghapus nol yang berfungsi sebagai penampung dan mencetak hasilnya.

Jika tidak ada vektor yang ditemukan, indeksnya akan -1 , jadi kami mengambil [0 ... 0] , yang akan mencetak array kosong.

Kode

q~                            e# Read from STDIN and evaluate the input.
  :+                          e# Push N, the sum of all elements of the resulting array.
     [40K9A6Z)U]              e# Push B := [40 20 9 10 6 4 0].
    _           m*            e# Push B**N, the array of all vectors of dimension N
                              e# and coordinates in B.
                  _::+        e# Copy and replace each vector by its sum.
                      @#      e# Get the first index of N.
                        =     e# Retrieve the corresponding element.
                         0-p  e# Remove 0's and print.
Dennis
sumber
Ini mungkin salah satu dari sedikit situasi di mana mengerjakan solusi dengan tangan akan lebih cepat daripada membiarkan kode selesai .. kerja bagus apa pun :)
Kade
2

Julia, 126 byte

r->(t=filter(i->all(j->j[4,6,9,10,20,40],i),partitions(sum(r)));show(!isempty(t)&&collect(t)[indmax(map(k->sum(k.^2),t))]))

Ini menciptakan fungsi tanpa nama yang menerima array sebagai input dan mencetak array atau boolean ke STDOUT, tergantung pada apakah ada solusi. Untuk menyebutnya, berikan nama, mis f=n->....

Penjelasan + tidak dikumpulkan:

function f(r)
    # Nugget pack sizes
    packs = [4, 6, 9, 10, 20, 40]

    # Filter the set of arrays which sum to the required number of nuggets
    # to those for which each element is a nugget pack
    t = filter(i -> all(j -> jpacks, i), partitions(sum(r)))

    # Print the boolean false if t is empty, otherwise print the array of
    # necessary nugget packs for which the sum of squares is maximal
    show(!isempty(t) && collect(t)[indmax(map(k -> sum(k.^2), t))])
end

Contoh:

julia> f([1])
false

julia> f([2,7,12,4,15,3])
[20,10,9,4]
Alex A.
sumber
1

Python 3 - 265 karakter

import itertools as i
n=list(map(int,input().split(',')));m=[]
for f in range(1,9):
 for j in range(6*f):
  for x in i.combinations((4,6,9,10,20,40,)*f,j+1):
   if sum(n)==sum(x):m.append(x)
if m!=[]:v=[sum(l**2for l in q)for q in m];print(m[v.index(max(v))])
else:print(0)

Menampilkan jarak:

import itertools as i
n=list(map(int,input().split(',')));m=[]
for f in range(1,5):
 for j in range(6*f):
\tfor x in i.combinations((4,6,9,10,20,40,)*f,j+1):
\t if sum(n)==sum(x):m.append(x)
\t\tif m!=[]:v=[sum(l**2for l in q)for q in m];print(m[v.index(max(v))])
else:print(0)

Lewati semua kasus uji

Catatan: Saya tidak tahu apakah ini akan melewati semua kasus karena sangat lambat ... Tetapi seharusnya ...

Peluruhan Beta
sumber
Tidak ada yang salah dengan ini sekarang, saya akan mengujinya dan lihat. Begitu sampai di rumah saya akan menambahkan referensi, program ungolfed yang saya gunakan untuk menghasilkan daftar yang ada di Gist. Sementara saya tidak menghitung waktu, saya percaya butuh sekitar 8-12 menit untuk semua kasus.
Kade
@ Vioz- Cemerlang! : D
Beta Decay
Sepertinya saya mungkin salah, setelah menguji 36 ia berhasil melewati sekitar 40 juta kombinasi (tepatnya 40.007.602) sebelum mengalami MemoryError. Ini mungkin keterbatasan mesin kerja saya, karena hanya memiliki memori 4GB.
Kade
@ Vioz- Hm ... Yah, tidak ada harapan bagi saya untuk melakukan pengujian pada ponsel saya ...
Beta Decay
1
@undergroundmonorail Jika Anda hanya menggunakannya sekali, maka untuk <= 4 karakter impor langsung lebih baik (5 break even). Tetapi jika Anda menggunakannya lebih dari sekali maka from blah import*itu selalu yang terbaik. Satu-satunya pengecualian yang dapat saya pikirkan di atas adalah jika Anda memiliki banyak imports, yang merupakan satu-satunya waktu yang terlintas di pikiran di mana assebenarnya berguna.
Sp3000
1

JavaScript, 261 256 261

d="length";function g(a){for(z=y=0;y<a[d];z+=+a[y++]);return z}x=[40,20,10,9,6,4];l=prompt().split(",");o=g(l);p=[];for(i=0;i<x[d];i++)r=g(p),s=r+x[i],(s<o-3||s==o)&&p.push(x[i]),(i==x[d]-1||40<o-r)&&r+x[i]<o-3&&(i=-1,0==i||o-r<p[p[d]-1]&&p.pop());g(p)==o&&p||0

Saya tidak yakin apakah ini baik-baik saja, sepertinya berfungsi tetapi saya pasti kehilangan beberapa hal.

Ini tampaknya tidak menjadi lambat meskipun, sampai 123456itu output [40 x 3086, 10, 6]hampir immediatly.

Penjelasan:

Mengurangi ukuran nugget (terbesar pertama)

  • Jika jumlah tumpukan ditambah ukuran nugget kurang dari sasaran - 3 -> dorong pada tumpukan
  • Jika ada lebih dari 40 yang tersisa -> reset penghitung loop
  • Jika jumlah tumpukan lebih dari sasaran ketika ukuran nugget terakhir tercapai -> pop elemen terakhir, setel ulang penghitung lingkaran
  • Jika jumlah tumpukan bertambah, kembalikan, jika tidak kembalikan 0

Untuk 199 | 1 tumpukan yang dibangun terlihat seperti ini

i | stack
0   [40]
0   [40, 40]
0   [40, 40, 40]
0   [40, 40, 40, 40]
0   [40, 40, 40, 40]
1   [40, 40, 40, 40, 20]
2   [40, 40, 40, 40, 20, 10]
3   [40, 40, 40, 40, 20, 10, 9]
4   [40, 40, 40, 40, 20, 10, 9]
5   [40, 40, 40, 40, 20, 10, 9]
==> [40, 40, 40, 40, 20, 10, 9]

Untuk 1

i | stack
0   []
1   []
2   []
3   []
4   []
5   []
==> 0
C5H8NNaO4
sumber
1
Pendekatan Anda sepertinya tidak memeriksa apakah tujuan dapat tercapai. 11cetak [6]dan 18cetak [10, 4].
Dennis
@ Dennis Hei, terima kasih sudah menunjukkannya. Sudah larut malam kemarin. Memperbaikinya selama 5 karakter. 18 dicetak [10,4]karena saya kehilangan sepasang parens. Cek itu memang salah, saya hanya memeriksa apakah ada setidaknya satu elemen di resultset, tidak jika dijumlahkan dengan benar. Saya tidak tahu apa yang saya pikirkan di sana
C5H8NNaO4