Apa yang ada di saus pasta saya?

37

Latar Belakang

Di Prancis, dan mungkin di seluruh Uni Eropa, setiap makanan yang tersedia untuk dijual harus mencantumkan bahan-bahan yang menyusunnya pada kemasannya, dalam urutan persentase penurunan berat . Namun, persentase pastinya tidak harus ditunjukkan, kecuali bahan tersebut disorot oleh teks atau gambar di sampulnya.

Sebagai contoh, saus tomat kemangi saya, hanya menunjukkan beberapa tomat merah besar dan daun kemangi yang indah pada kemasannya, memiliki indikasi sebagai berikut:

Bahan: Tomat 80%, bawang merah, basil 1,4%, garam laut, bawang putih tumbuk, gula tebu mentah, minyak zaitun extra virgin, lada hitam.

Kedengarannya gurih, tapi ... berapa banyak bawang yang akan saya makan , tepatnya?

Tantangan

Diberikan daftar persentase berat dalam urutan menurun, akhirnya tidak lengkap, menampilkan daftar lengkap persentase berat minimum dan maksimal yang mungkin dapat ditemukan dalam resep.

  • Anda dapat menulis fungsi, atau program lengkap.
  • The masukan bisa dalam bentuk yang wajar (array angka atau daftar string, misalnya). Nilai pecahan harus didukung setidaknya ke satu tempat desimal. Persentase berat badan yang hilang dapat diwakili dengan cara yang konsisten dan tidak ambigu ( 0, '?'atau null, misalnya). Anda dapat mengasumsikan bahwa input akan selalu dikaitkan dengan resep yang valid ( [70]dan[∅, ∅, 50] tidak valid, misalnya).
  • The Output dapat dalam bentuk yang wajar (satu array untuk kedua persentase berat minimal dan maksimal, atau satu daftar doublet, misalnya). Persentase minimal dan maksimal dapat dalam urutan apa saja ( [min, max]dan [max, min]keduanya dapat diterima). Persentase berat yang tepat tidak perlu diproses secara berbeda dari persentase lainnya dan dapat direpresentasikan dengan nilai minimal dan maksimal yang sama.

Aturan standar untuk berlaku: saat Anda mengetik kode Anda, hidangan pasta saya menjadi dingin, sehingga pengiriman terpendek menang.

Contohnya

Karena masalah ini lebih sulit daripada yang terlihat pada pandangan pertama, berikut adalah resolusi langkah demi langkah dari beberapa kasus.

[40, ∅, ∅]

Mari kita sebut masing x- masing dan ydua persentase yang hilang.

  • Karena muncul setelah bahan pertama pada 40%, xtidak bisa lebih tinggi dari 40% itu sendiri.
    [40, [?, 40], [?, ?]]
  • Jumlah dari dua persentase yang hilang selalu 60%. Akibatnya:
    • Jika xmengambil nilai maksimalnya , maka ymengambil nilai minimalnya , yang karenanya 60% - 40% = 20%.
      [40, [?, 40], [20, ?]]
    • Jika xmengambil nilai minimalnya , maka yambil nilai maksimalnya . Tapi xtidak boleh lebih rendah dari itu y, jadi dalam hal ini, x= y= 60% / 2 = 30%.
      [40, [30, 40], [20, 30]]

[70, ∅, ∅, 5, ∅]

Mari kita sebut masing-masing x, ydan ztiga persentase yang hilang.

  • Persentase minimal dan maksimal untuk zharus antara 0% dan 5%. Mari kita asumsikan z= 0% sejenak. Jumlah dari dua persentase yang hilang selalu 25%. Akibatnya:
    [70, [?, ?], [?, ?], 5, [0, 5]]
    • Jika ymengambil nilai minimalnya , 5%, kemudian xmengambil nilai maksimalnya , yang karenanya 25% - 5% = 20%.
      [70, [?, 20], [5, ?], 5, [0, 5]]
    • Jika ymengambil nilai maksimalnya , maka xmengambil nilai minimalnya . Tetapi xtidak boleh lebih rendah dari itu y, jadi dalam hal ini, x= y= 25% / 2 = 12,5%.
      [70, [12.5, 20], [5, 12.5], 5, [0, 5]]
  • Mari kita verifikasi bahwa semuanya baik-baik saja jika kita asumsikan sekarang z = 5%. Jumlah dari dua persentase yang hilang selalu 20%. Akibatnya:
    • Jika ymengambil nilai minimalnya , 5%, kemudian xmengambil nilai maksimalnya , yaitu 20% - 5% = 15%. Kasing ini sudah termasuk dalam rentang yang dihitung sebelumnya.
    • Jika ymengambil nilai maksimalnya , maka xmengambil nilai minimalnya . Tetapi xtidak boleh lebih rendah dari itu y, jadi dalam hal ini, x= y= 20% / 2 = 10%. Kasing ini sudah termasuk dalam rentang yang dihitung sebelumnya untuk y, tetapi tidak untuk x.
      [70, [10, 20], [5, 12.5], 5, [0, 5]]

Uji kasus

Input:  [∅]
Output: [100]

Input:  [70, 30]
Output: [70, 30]

Input:  [70, ∅, ∅]
Output: [70, [15, 30], [0, 15]]

Input:  [40, ∅, ∅]
Output: [40, [30, 40], [20, 30]]

Input:  [∅, ∅, 10]
Output: [[45, 80], [10, 45], 10]

Input:  [70, ∅, ∅, ∅]
Output: [70, [10, 30], [0, 15], [0, 10]]

Input:  [70, ∅, ∅, 5, ∅]
Output: [70, [10, 20], [5, 12.5], 5, [0, 5]]

Input:  [30, ∅, ∅, ∅, 10, ∅, ∅, 5, ∅, ∅]
Output: [30, [10, 25], [10, 17.5], [10, 15], 10, [5, 10], [5, 10], 5, [0, 5], [0, 5]]
Lubang hitam
sumber
5
Sepenuhnya Tidak Berhubungan
Magic Gurita Guci
3
Saya akan menambahkan penjelasan selangkah demi selangkah dari input-to-output untuk [40, ∅, ∅]dan [70, ∅, ∅, 5, ∅]untuk membuat hal-hal sedikit lebih jelas. Suatu tantangan harus jelas tanpa melihat pada test case, yang bukan merupakan case saat ini. Jika saya memahaminya dengan benar [40, ∅, ∅]: 60 lebih banyak diperlukan untuk 100%, dibagi dua . Yang pertama harus 30 atau lebih tinggi (kalau tidak yang kedua akan di atasnya, yang seharusnya tidak mungkin ketika mereka dalam urutan). Selain itu, tidak bisa di atas 40, jadi yang pertama menjadi [30,40], dan yang kedua menjadi [(100-40-40=)20, (100-40-30=)30].
Kevin Cruijssen
Secara konsisten [min,max]/ [max,min]atau campuran diizinkan?
14m2
@ l4m2 Mencampur [min,max]dan [max,min]merupakan batas yang dapat diterima, tetapi karena tidak dapat menghasilkan hasil yang ambigu, saya akan mengatakan tidak apa-apa.
Blackhole
Mungkin saya kehilangan sesuatu, tetapi mengapa [70, 12, 11, 5, 2]tidak berhasil untuk contoh kedua Anda? Jika berhasil, minimum untuk xmenjadi kurang dari 12.5.
DLosc

Jawaban:

11

JavaScript (ES6), 252 byte

Mengharapkan 0persentase yang hilang. Menghasilkan sepasang nilai minimum dan maksimum untuk semua entri.

a=>(g=a=>(h=(M,I,J=I^1)=>a.some((x,i)=>a.map((y,j)=>s-=j-i?M(j,i)-i?y[I]:M(w=y[I],z=x[J])-z||w==z?w:++k&&z:y[J],s=100,k=1,X=x)&&(I?-s:s)<0)?X[J]=M(X[I],X[J]+s/k):0)(Math.max,0)+h(Math.min,1)?g(a):a)(a.map((n,i)=>[n?p=n:a.find(n=>i--<0&&n)||0,p],p=100))

Cobalah online!

Bagaimana?

Inisialisasi

Kami pertama-tama mengganti setiap nilai dalam larik input a [] dengan rentang sebesar mungkin.

a.map((n, i) =>       // for each value n at position i in a[]:
  [                   //   generate a [min, max] array:
    n ?               //     if n is not 0:
      p = n           //       use n as the minimum and save it in p
    :                 //     else:
      a.find(n =>     //       find the first value n
        i-- < 0 &&    //         which is beyond the current value
        n             //         and is not equal to 0
      ) || 0,         //       or use 0 as a default value
    p                 //     use p as the maximum
  ],                  //   end of array declaration
  p = 100             //   start with p = 100
)                     // end of map()

Contoh:

[ 0 ] --> [ [ 0, 100 ] ]
[ 30, 0, 5, 0 ] --> [ [ 30, 30 ], [ 5, 30 ], [ 5, 5 ], [ 0, 5 ] ]

Fungsi utama

Fungsi utama adalah h () . Tampaknya entri pertama yang tampaknya tidak konsisten ketika kami mencoba memperkecil atau memaksimalkannya. Jika ditemukan, pembaruan ke nilai yang setidaknya dapat diterima untuk sementara, mengingat rentang lainnya.

Dibutuhkan sebagai input baik M = Math.max / I = 0 atau M = Math.min / I = 1 dan mendefinisikan J sebagai I XOR 1 .

Karena h () ditulis untuk mendukung pass minimalisasi dan maksimalisasi, kode ini agak sulit dikomentari. Itu sebabnya kami akan fokus hanya pada pemaksimalan pass, yang kami miliki M = Math.max , I = 0 dan J = 1 . Dengan parameter ini, kode tersebut berbunyi sebagai berikut:

a.some((x, i) =>              // for each range x at position i in a[] (tested range):
  a.map((y, j) =>             //   for each range y at position j in a[] (reference range):
    s -=                      //     update s:
      j - i ?                 //       if i is not equal to j:
        Math.max(j, i) - i ?  //         if j > i:
          y[0]                //           the reference range is beyond the tested range
                              //           so we just use the minimum value of the y range
        :                     //         else:
          Math.max(           //           take the maximum of:
            w = y[0],         //             w = minimum value of the y range
            z = x[1]          //             z = maximum value of the x range
          ) - z ||            //           if it's not equal to z
          w == z ?            //           or they are equal (i.e. if w <= z):
            w                 //             use w
          :                   //           else:
            ++k && z          //             increment the counter k and use z
      :                       //       else:
        y[1],                 //         use the maximum value of the y range
    s = 100,                  //     start with s = 100
    k = 1,                    //     start with k = 1
    X = x                     //     save the range x in X
  ) &&                        //   end of map()
  (0 ? -s : s) < 0            //   abort if s < 0 (i.e. if we've subtracted more than 100)
) ?                           // end of some(); if truthy:
  X[1] = Math.max(            //   update the maximum value of the faulty range to:
    X[0],                     //     either the minimum value
    X[1] + s / k              //     or the maximum value, less the correction
  )                           //   whichever is greater
:                             // else:
  0                           //   do nothing

Rekursi

Fungsi rekursif g () terus memanggil h () sampai tidak ada jalur meminimalkan atau memaksimalkan yang mengarah ke koreksi baru, dan akhirnya mengembalikan hasil akhir.

g = a => h(Math.max, 0) + h(Math.min, 1) ? g(a) : a
Arnauld
sumber
Bagus sekali :-)!
Blackhole
4
@ Blackhole Terima kasih! Dan BTW: saus pasta saya sendiri berbunyi [38,0,10,0,0,0,0,0,0,0].
Arnauld