Спустіть жолоби та захистіть джекпот


23

Ви збираєтесь брати участь у ігровому шоу. Один із викликів працює наступним чином:

  • Перша кімната містить велику кількість однакових куль.
  • Друга кімната містить ряд жолобів, у кожному з яких є датчик, який підраховує, скільки кульок було розміщено в ній. Куля, поміщена в жолоб, потім неможливо отримати.
  • Кожен жолоб спрацьовує після того, як у нього поміститься певна кількість кульок (його кількість спускових гачок ). Коли вона спрацьовує, вона спалахує вогнями, видає шум і не залишає вас сумнівів у тому, що воно спрацювало.
  • Ви повинні запустити Nжолоби, щоб перейти до наступного виклику.
  • Ви знаєте кількість спускових гачок, але не відповідність між лічильником і жолобом.
  • У вас є одна можливість взяти кульки з першої кімнати в другу. Після того, як ви помістите кулю в жолоб, ви не зможете повернутися до більшої кількості кульок.
  • Кожна куля, яку ви берете, віднімає гроші з джекпота.

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

Приклад

Припустимо, кількість спускових гачок становить 2, 4 та 10, і вам потрібно пропустити 2 жолоби, щоб пройти. Існує стратегія передачі з 10 куль: в перший жолоб розмістіть до 4 кульок, в другому жолоб до 4 кульок, а в третьому жолоб до 4 кульок. Оскільки один з трьох жолобів спрацює лише через 2 кулі, ви використовуєте лише 10. Немає стратегії, яка б гарантувала роботу з меншою ніж 10, тому це правильний вихід.

Вхідні дані

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

Ви можете припустити, що всі входи більше нуля, і що кількість жолобів, які повинні спрацьовувати, не перевищує кількість жолобів.

Ви також можете припустити, що підрахунки відсортовані (зростаючі чи низхідні), якщо ви чітко заявляєте про це у своїй відповіді.

Вихід

Вихід повинен бути єдиним цілим числом, даючи кількість кульок, необхідних оптимальній стратегії.

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

Формат: N counts solution

1 [2 4 10] 6
2 [2 4 10] 10
3 [2 4 10] 16
1 [3 5 5 5 5 5 5 5 5 5] 5
2 [1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 8 11] 8
2 [1 2 6 6 6 6 6 6 6 10] 16
2 [1 2 3 3 4 4 6 6 6 11] 17
3 [1 2 3 4 5 5 6] 16
3 [2 4 7 7 7 7 7 7 7] 21
5 [1 2 2 3 3 3 3 3 5 9 9 11] 27
2 [5 15 15] 25
1 [4 5 15] 10
3 [1 4 4 4] 10
2 [1 3 4] 6
2 [1 3 3 8] 8

Попередження: не намагайтеся ніндзя!
Ерік Аутгольфер

1
Чи можете ви поясніть, чому останній тестовий випадок дає 10? Ви не повинні мати одне місце принаймні по 4 у кожному, щоб переконатися, що принаймні один тригер? Я, мабуть, занадто німий і недостатньо добре прочитав питання, але не розумію.
Містер Xcoder

2
@Rod Вам потрібно буде розмістити лише 5 у двох з них, перш ніж гарантовано спрацювати, 5 * 2 = 10
H.PWiz

3
@ H.PWiz Спасибі, тепер отримав це. Виклик зараз здається набагато складнішим ...
Містер Xcoder

1
@ Mr.Xcoder, так, але ви повинні бути впевнені в успіху в гіршому випадку.
Пітер Тейлор

Відповіді:


4

Пітон, 222 198 байт

def S(G,P,T=0):
 T=T or[0]*len(P);r=[0]*(sum(t>=p for t,p in zip(T,P))>=G)
 for i,t in enumerate(T):
    if t<max(P):a=next(p for p in P if p>t)-t;T[i]+=a;r+=[a+S(G,P,sorted(T))];T[i]-=a
 return min(r)

Використання є S(2, (2, 4, 10)).

Для того, щоб протестувати цю програму на будь-якій пристойній швидкості, додайте пам'ять, поставивши це після визначення функції:

old_s = S
mem = {}
def S(G, P, T=0):
    k = (G, tuple(P), T and tuple(T) or 0)
    if k in mem: return mem[k]
    r = old_s(G, P, T)
    mem[k] = r
    return r

Ми робимо динамічне програмування на масиві T, який містить кількість кульок, які ми кинули в кожен жолоб, спочатку всі нулі. Не надаючи суворих доказів, я стверджую, що ми можемо тримати сортування Т у всі часи, тобто припустимо, що ми завжди кидаємо в останній жолоб більшість кульок, що, у свою чергу, ми будемо вважати, що це найбільший жолоб.

Якщо тоді T, коли збігається елемент для елемента з P (який є нашою вхідною проблемою), має принаймні G (що є нашою метою) елементів більше, ми знайшли рішення, і повернемо 0, тому що нам потрібно кинути 0 більше кульок, щоб знайти рішення. Це означає, що якщо G дорівнює 1, наш найменший викид у жолоб повинен містити рівну або більшу кількість кульок, ніж найменша вимога жолоба, і так далі для більшого G.

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


215 байт шляхом видалення continue.
Містер Xcoder

1

4

Haskell, 124 117 100 98 91 80 78 байт

Збережено 11 байт завдяки @Peter Taylor

0#_=0
n#a=minimum$zipWith(\x y->x*y+(n-1)#(snd.splitAt y$a))a[1..length a-n+1]

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

(#) приймає в якості аргументів ціле число і список цілих чисел у порядку зменшення

Використання є 1#[10,4,2]

Пояснення:

Для кожного значення, x, у положенні i (1-ідекс) у списку, найкраща тактика для видалення цього елемента (або деякої кількості елементів, меншої або рівної x) - це влити x кульки в i жолоби.

Для кожного елемента, x, у положенні i у списку (n #) обчислюється x * i + ((n-1) #) списку поза позицією i (поки n не дорівнює 0). Тоді він займає мінімум усіх перевірених можливостей.


3

Haskell , 54 байти

(%)0
(p%l)n|h:t<-l=p+min(p%t$n)(h%t$n-1)|n<1=p|1>0=1/0

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

Складає список у порядку зростання.


Зауважте, що самостійно: наступного разу наполягайте, що вихід має бути цілим типом.
Пітер Тейлор

1
Я не знаю достатньо Haskell, щоб розібратися в цьому, чи можете ви додати пояснення?
orlp

2

Пітон, 73 байти

f=lambda n,c:n and min(c[i]*-~i+f(n-1,c[-~i:])for i in range(len(c)-n+1))

Порт відповіді Хаскелла від H.PWiz. Потрібно вводити у порядку зменшення.


1

CJam (35 байт)

{:A,,e!f<{$__(;A,+.-\Af=.*1bz}%:e<}

Демонстрація в Інтернеті

Приймає введення як N countsприпущення, яке countsсортується у порядку зростання.

Розсічення

Позначте підрахунки у порядку зменшення у вигляді 1-індексованого масиву C(тому другим елементом Cє другий за величиною підрахунок). Припустимо, що ми закінчуємо перемогу, спрацьовуючи жолоби C[a_0], C[a_1], ... C[a_{N-1}]. Тоді, в гіршому випадку, для кожного C[a_i]ми помістили принаймні C[a_i]кульки в кожен жолоб 1до a_i. Тому ми кладемо C[a_{N-1}]кульки в a_{N-1}жолоби, додаткові C[a_{N-2}]кульки в a_{N-2}них, ...

За кожним підмножиною Nпідрахунків, що дає нам найменшу суму? Тоді ми повинні прагнути виграти з цим підмножиною рахунків.

Примітка: Код фактично використовує підрахунки у порядку зростання, але я думаю, що порядок спадання є більш інтуїтивним.

{         e# Define a block
  :A      e#   Store the sorted counts as A
  ,,e!f<  e#   Get all N-element subsets of A's indices
  {       e#   Map over these subsets S:
    $__   e#     Sort the subset and get a couple of copies
    (;A,+ e#     Remove the first element from one copy and append len(A)
    .-    e#     Pointwise subtraction, giving [S[0]-S[1] S[1]-S[2] ...]
    \Af=  e#     Get the counts [A[S[0]] A[S[1]] ...]
    .*    e#     Pointwise multiplication
    1bz   e#     Sum and take absolute value, giving the worst case score
  }%
  :e<     e#   Select the minimum worst case score
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.