Що в моєму соусі з макаронами?


37

Фон

У Франції, і, мабуть, у решті країн Європейського Союзу, будь-яка їжа, доступна для продажу, повинна перераховувати інгредієнти, що входять до складу упаковки, у ваговому відсотку за спаданням . Однак точний відсоток не потрібно вказувати, якщо інгредієнт не буде виділений текстом або зображенням на обкладинці.

Наприклад, мій томатний соус із базиліком, на його упаковці є лише великі червоні помідори та красиві листя базиліка, має такі ознаки:

Інгредієнти: Помідори 80%, цибуля на шматочках, базилік 1,4%, морська сіль, часникове пюре, сирий тростинний цукор, оливкова олія надзвичайної олії, чорний перець.

Це звучить пікантно, але… скільки цибулі я точно з’їв ?

Виклик

Враховуючи перелік вагових відсотків у порядку зменшення, з часом неповний, виведіть повний перелік мінімальних і максимальних відсоткових відсотків, які, можливо, можна знайти в рецепті.

  • Ви можете написати або функцію, або повну програму.
  • Введення даних може бути в будь-якій розумній формі (наприклад, масив чисел або список рядків). Дробові значення повинні підтримуватися принаймні до одного десяткового знака. Відсутній ваговій відсоток може бути представлений в будь-якому послідовному і недвозначному способі ( 0, '?'або null, наприклад). Можна припустити, що введення завжди буде пов’язане з дійсним рецептом ( [70]і [∅, ∅, 50]недійсним, наприклад).
  • Вихід може бути в будь-якому розумному формі (один масив для обох з мінімального і максимального процентного ваги, або один список дублетів, наприклад). Мінімальний і максимальний відсотки можуть бути в будь-якому порядку ( [min, max]і [max, min]обидва прийнятні). Точні відсоткові ваги не потрібно обробляти інакше, ніж інші відсотки, і можуть бути представлені рівними мінімальними та максимальними значеннями.

Застосовуються стандартні правила для : поки ви вводите код, моє блюдо з макаронами охолоджується, тому виграє найкоротше подання.

Приклади

Оскільки ця проблема важче, ніж може здатися на перший погляд, ось покрокове вирішення кількох випадків.

[40, ∅, ∅]

Назвемо відповідно xі yдва пропущені відсотки.

  • Оскільки він надходить після першого інгредієнта на 40%, він xне може бути вище 40%.
    [40, [?, 40], [?, ?]]
  • Сума двох відсутніх відсотків завжди становить 60%. Отже:
    • Якщо xприймає його максимальне значення, то yприймає його мінімальне значення, яке, отже, становить 60% - 40% = 20%.
      [40, [?, 40], [20, ?]]
    • Якщо xприймає своє мінімальне значення, то yприймає його максимальне значення. Але xне може бути нижче y, тому в цьому випадку x= y= 60% / 2 = 30%.
      [40, [30, 40], [20, 30]]

[70, ∅, ∅, 5, ∅]

Давайте назвемо відповідно x, yі zтри відсутні відсотки.

  • Мінімальний і максимальний відсотки для zобов'язково становлять від 0% до 5%. Припустимо, zна хвилину = 0%. Сума двох відсутніх відсотків завжди становить 25%. Отже:
    [70, [?, ?], [?, ?], 5, [0, 5]]
    • Якщо yприймає його мінімальне значення, 5%, то xприймає його максимальне значення, яке, отже, становить 25% - 5% = 20%.
      [70, [?, 20], [5, ?], 5, [0, 5]]
    • Якщо yприймає своє максимальне значення, то xприймає своє мінімальне значення. Але xне може бути нижче y, тому в цьому випадку x= y= 25% / 2 = 12,5%.
      [70, [12.5, 20], [5, 12.5], 5, [0, 5]]
  • Перевіримо, що все нормально, якщо зараз припустити, що z= 5%. Сума двох відсутніх відсотків завжди становить 20%. Отже:
    • Якщо yприймає його мінімальне значення, 5%, то xприймає його максимальне значення, яке, отже, становить 20% - 5% = 15%. Цей випадок вже включений до раніше обчислених діапазонів.
    • Якщо yприймає його максимальне значення, то xприймає його мінімальне значення. Але xне може бути нижче y, тому в цьому випадку x= y= 20% / 2 = 10%. Цей випадок уже включений у раніше обчислений діапазон дляy , але не для x.
      [70, [10, 20], [5, 12.5], 5, [0, 5]]

Тестові справи

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


3
Я б додав покрокове пояснення введення-виведення для [40, ∅, ∅]і [70, ∅, ∅, 5, ∅]зробити все трохи більш чітким. Завдання має бути зрозумілим, не дивлячись на тестові випадки, що зараз не так. Якщо я правильно це розумію [40, ∅, ∅]: на 100% потрібно ще 60, розділене на ці два . Перший повинен бути 30 або вище (інакше другий буде над ним, що не повинно бути можливим, коли вони в порядку). Крім того, воно не може бути вище 40, тому перше стає [30,40], а друге стає [(100-40-40=)20, (100-40-30=)30].
Кевін Крейссен

Послідовно [min,max]/ [max,min]або змішано дозволено?
l4m2

@ L4m2 Змішування [min,max]і [max,min]є прикордонним прийнятним, але так як вона не може привести до неоднозначних результатів, я б сказав , що це нормально.
Blackhole

Можливо, я чогось пропускаю, але чому це [70, 12, 11, 5, 2]не працює для вашого другого прикладу? Якщо це дійсно спрацює, мінімальний розмір xбуде меншим за 12.5.
DLosc

Відповіді:


11

JavaScript (ES6), 252 байти

Очікує 0відсутніх відсотків. Повертає пару мінімальних та максимальних значень для всіх записів.

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

Спробуйте в Інтернеті!

Як?

Ініціалізація

Спочатку замінюємо кожне значення у вхідному масиві a [] на максимально можливий діапазон.

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()

Приклади:

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

Основна функція

Основна функція h () . Перший запис виглядає непослідовим, коли ми намагаємося його мінімізувати чи максимально збільшити. Якщо він знайде один, він оновлює його до значення, яке є принаймні тимчасово прийнятним, враховуючи інші діапазони.

Він приймає як вхід або M = Math.max / I = 0, або M = Math.min / I = 1 і визначає J як I XOR 1 .

Оскільки h () було написано для підтримки як мінімізації, так і максимізації пропусків, код трохи складний для коментарів. Тому ми зупинимося лише на максимізаційному проході, для якого у нас M = Math.max , I = 0 і J = 1 . За допомогою цих параметрів код звучить так:

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

Рекурсія

Рекурсивна функція g () продовжує викликати h (), поки ні мінімізація, ні максимальний пропуск не призводять до нового виправлення, і в кінцевому підсумку не повертають кінцевий результат.

g = a => h(Math.max, 0) + h(Math.min, 1) ? g(a) : a

Чудово зроблено :-)!
Blackhole

4
@Blackhole Дякую! І BTW: мій власний макаронний соус читає [38,0,10,0,0,0,0,0,0,0].
Арнольд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.