Визначте, чи система монет є канонічною


48

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

Візьмемо такий приклад:

У нас є монети 4 ¢, 3 ¢ та 1 ¢. Ми хочемо зробити 6 ¢.

Алгоритм касира спочатку вибере стільки найбільшої монети (одну 4 ¢ для початку) і відніме і повторить. Це призведе до отримання однієї монети 4 and та двох 1 ¢ монети загалом 3 монети.

На жаль, для алгоритму існує спосіб скласти 6 ¢ лише двома монетами (дві 3 ¢ монети).

Система змін буде вважатися канонічною iff для всіх цілих значень Алгоритм касира знайде оптимальну кількість монет.

Завдання

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

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

Це код, котрий виграє найменше байтів у гольф.

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

Цей список аж ніяк не вичерпний, ваша програма повинна працювати на всіх дійсних даних

1, 3, 4       -> 0
1, 5, 10, 25  -> 1
1, 6, 10, 25  -> 0
1, 2, 3       -> 1
1, 8, 17, 30  -> 0
1, 3, 8, 12   -> 0
1, 2, 8, 13   -> 0
1, 2, 4, 6, 8 -> 1

@Geobits не в кожному випадку означає більше, що різниця зростає або дорівнює від найменшої монети до найбільшої
Йорг Гюльсерманн

@ JörgHülsermann Це теж не дуже добре. [1, 6, 13] має різницю в зростанні, але вона все ще не вдається на щось на зразок 18 (13 + 1 * 5 замість 6 * 3).
Геобіць

16
Вони називаються Canonical Coin Systems . У цьому короткому документі наведено алгоритм багаточленного часу для перевірки того, чи є система монет канонічною (хоча менш ефективний метод може бути гравцем). Цікавий тестовий випадок - це 37 центів 25, 9, 4, 1цієї посади з математики .SE ) - навіть якщо кожна монета більша за суму менших, нежиті 25, 4, 4, 4б'ють жадібніших 25, 9, 1, 1, 1.
xnor

1
@xnor Зауважте, що 9, 4, 1-> 4, 4, 4бути кращим, ніж 9, 1, 1, 1є більш жорстким прикладом.
isaacg

Відповіді:


9

Haskell, 94 87 82 байт

f s=and[j i-2<j(i-x)|let j i=last$0:[1+j(i-x)|x<-s,x<i],i<-[1..2*last s],x<-s,x<i]

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

це рішення передбачає, що вхід сортується.

Достатньо перевірити доказ у два рази найбільше число: припустимо, що система не є канонічною для деякого числа i, і нехай kнайбільше число у списку не перевищує i. припустимо, що i >= 2kі система є канонічною для всіх чисел менше, ніж i.

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

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

Редагувати: п’ять байтів вимкнено завдяки Ørjan Johansen!


1
Ви можете зберегти байт, використовуючи letзамість where. Ви можете поставити його як |let ...захист шаблону після f s, або всередині списку.
Ørjan Johansen

1
Ще чотири байти з j i=last$0:[1+j(i-k)|k<-s,k<i].
Ørjan Johansen

5

Піт, 18 15 байт

!x#eST.gsky_S*e

Тестовий набір

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

Потім я знаходжу таку пару наступним чином:

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

Пояснення:

!x#eST.gsky_S*e
!x#eST.gsky_S*eQQ   Variable introduction.
                    Q = eval(input()) - sorted list of coins.
              eQ    Greatest coin in the list
             *  Q   Repeat that many times.
            S       Sort the coins
           _        Reverse, so we have the coins in descending order.
          y         Form all subsets, in increasing size then
                    decreasing lexicographic order.
      .gsk          Group by sum
 x#                 Filter by the index in the group of
   eST              The last element lexicographically (greedy solution).
!                   Logically negate.

Дуже приємно - будь-яка ідея, чому він висить на herokuapp для [1, 2, 4, 6, 8] і вбивається /opt/tryitonline/bin/pyth: line 5: 28070 Killed ... Exit code: 137в TIO? Тільки поза пам'яттю?
Джонатан Аллан

Для цього використовується 2 ^ (число монет * остання монета) байтів пам'яті. Отже, для вашого прикладу, 2 ^ 40. Не так багато машин з терабайтом оперативної пам’яті
isaacg

Я вважав, що це може бути так, що опис алгоритму має сенс, але я не підраховував числа - так просто так швидко!
Джонатан Аллан

5

PHP, 323 байт

Точно так само, як і інші рахують монети до суми двох останніх елементів у масиві

<?function t($g){rsort($g);$m=array_slice($g,1);for($y=1,$i=$g[0];$i<$g[0]+$m[0];$i++){$a=$b=$i;$p=0;$r=$s=[];while($a||$b){$o=$n=0;$g[$p]<=$a?$a-=$r[]=$g[$p]:$o=1;($m[$p]??1)<=$b?$b-=$s[]=$m[$p]:$n=1;$p+=$o*$n;}$y*=count($r)<=count($s);}return$y;}for($i=0,$t=1;++$i<count($a=$_GET[a]);)$t*=t(array_slice($a,0,$i+1));echo$t;

Моя найкраща і найдовша відповідь, я вважаю,> 370 байт

Я даю лише розширену версію, тому що це довше, ніж моя відповідь раніше

for($x=1,$n=0,$f=[];++$n<count($a)-1;){
$z=array_slice($a,0,$n+1);
$q=$a[$n]-$a[$n-1];
$i=array_fill(1,$c=max($a[$n+1]??1,11),"X");#$q*$a[$n]
$f=range($a[$n],$c,$q);

$f[]=2*$a[$n];
for($d=[$z[$n]],$j=0;$j<$n;){
   $f[]=$a[$n]+$d[]=$z[$n]-$z[$j++]; 
}

while($f){
    $i[$t=array_pop($f)]="T";
    foreach($d as $g)
    if(($l=$t+$g)<=$c)$f[]=$l;
}

foreach($i as$k=>$v){
    if(in_array($k,$z))$i[$k]="S";
}
#var_dump($i);
if($i[$a[$n+1]]=="X")$x*=0;
}
echo$x;

Пояснення до цієї відповіді

Інтернет-версія

  1. Встановіть усе в масиві значення false == X

  2. Встановіть усі числа в масиві, яким ви керуєте, S

  3. Виявлені відмінності між останнім S та іншим S або 0

  4. Почніть нарешті S у масиві

  5. Встановіть усе число D, де Last S + одна з усіх відмінностей

  6. Почніть взагалі D

  7. Встановіть у масиві значення "T" на D

  8. GOTO 5 Повторіть це з усіма знайденими DI, це не дуже в коді

  9. Якщо наступний елемент масиву має X - це помилковий випадок істинний

Додаткова різниця в кроці є у фрагменті 3 Між 1 та 4 є 2 X Це означає, що вам потрібен другий D за кроком 5. Після цього значення в цьому випадку 10 - всі випадки справжні, я міг бачити, поки що стосунки є між різницею та кількістю в масиві, яким ви керуєте, щоб обчислити, скільки D (крок 5) потрібно, щоб отримати точку, перш ніж знайти останній помилковий випадок.

Ви встановлюєте кілька значень з останнього елемента безпосередньо на true. Ці Бали можуть змінити значення, щоб вирішити, чи могло бути, що жадібний кількість монет із наступним значенням такий самий, як кратний останній у масиві. З іншого боку ви можете встановити ворога

  1. Встановити першого ворога на рівні 1 + Останній

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

  3. Почніть з останнього ворога Goto 2

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

table{width:80%}
td,th{width:45%;border:1px solid blue;}
<table>
  <caption>Working [1,4]</caption>
<tr><th>Number</th><th>Status</th></tr>
<tr><td>1</td><td>S</td></tr>
<tr><td>2</td><td>X</td></tr>
<tr><td>3</td><td>X</td></tr>
<tr><td>4</td><td>S</td></tr>
<tr><td>5</td><td>X</td></tr>
<tr><td>6</td><td>X</td></tr>
<tr><td>7</td><td>D3</td></tr>
<tr><td>8</td><td>D4</td></tr>
<tr><td>9</td><td>X</td></tr>
<tr><td>10</td><td>D3D3</td></tr>
<tr><td>11</td><td>D4D3</td></tr>
<tr><td>12</td><td>D4D4</td></tr>
<tr><td>13</td><td>D3D3D3</td></tr>
<tr><td>14</td><td>D4D3D3</td></tr>
<tr><td>15</td><td>D4D4D4</td></tr>
<tr><td>16</td><td>D4D4D3</td></tr>
</table>
<ul>
  <li>S Number in Array</li>
  <li>D Start|End point TRUE sum Differences from last S</li>
  <li>X False</li>
  </ul>

плюс? Байти Дякую @JonathanAllan, що ти дав мені неправильні тестові справи
262 байт Майже, але недостатньо добре 4 помилкові тести на даний момент

тестові випадки [1,16,256] раніше повинні бути правдивими після помилкових

<?for($q=[1],$i=0,$t=1,$w=[0,1];++$i<count($a=$_GET[v]);$w[]=$a[$i],$q[]=$m)($x=$a[$i]-$a[$i-1])>=($y=$a[$i-1]-$a[$i-2])&&((($x)%2)==(($m=(($a[$i]+$x)*$a[$i-1])%$a[$i])%2)&&$m>array_sum($q)||(($x)%2)==0&&(($a[$i]-$a[$i-2])*2%$y)==0||in_array($m,$w))?:$t=0;echo$t;

Порядок висхідного масиву

Пояснення

for($q=[1],$i=0,$t=1,$w=[0,1] # $t true case $q array for modulos $w checke values in the array
;++$i<count($a=$_GET[v])   #before loop
;$w[]=$a[$i],$q[]=$m) # after loop $q get the modulo from the result and fill $w with the checked value

($x=$a[$i]-$a[$i-1])>=($y=$a[$i-1]-$a[$i-2]) 
# First condition difference between $a[i] and $a[$i-1] is greater or equal $a[$i-1] and $a[$i-2]
# if $a[$-1] == 1 $a[$i-2] will be interpreted as 0
&&  ## AND Operator with the second condition
(
(($x)%2)==   # See if the difference is even or odd
(($m=(($a[$i]+$x)*$a[$i-1])%$a[$i])%2)&&$m>array_sum($q)
# After that we multiply the result with the lower value *$a[$i-1]
    # for this result we calculate the modulo of the result with the greater value %$a[$i]
    # if the difference and the modulo are both even or odd this belongs to true
# and the modulo of the result must be greater as the sum of these before
    # Ask me not why I have make try and error in an excel sheet till I see this relation
||
(($x)%2)==0&&(($a[$i]-$a[$i-2])*2%$y)==0 # or differce modulator is even and difference $a[$i],$a[$i-1] is a multiple of half difference $a[$i-1],$a[$i-2] 
||
in_array($m,$w) # if the modulo result is equal to the values that we have check till this moment in the array we can also neglect the comparison
)
?:$t=0; # other cases belongs to false
echo$t; #Output

Виглядає так, що те, що я бачив у таблиці, містить значення з [1,2,3,4,5,6], і я змінюю лише останній елемент до 9. Для 2to3 та 4to5 ми створюємо значення нижнього значення в модульний розрахунок

table{width:95%;}th,td{border:1px solid}
<table><tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>35</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>2</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>0</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>7</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>45</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>3</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>3</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>8</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>55</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>7</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>4</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>0</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>9</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>65</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>2</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>0</td></tr></table>


Чому ви розколюєтесь, ", "коли можете розколотися ","; чому ти розбився, коли ти міг взяти список; чому ви сортуєте, коли ви могли взяти відсортований список? (Я також не впевнений, що метод, який ви використовуєте, є непогрішним, чи є у вас докази, тому що література, яку я проглянув, здається, підказує, що це важче, ніж те, що я думаю, що робить ваш код.)
Джонатан Аллан

@ JörgHülsermann Вибачте, якщо я викликав замішання, хоча це було інакше, перш ніж ви зможете взяти відсортований список, якщо ви захочете.
Пшеничний майстер

Боюся, я думаю, що вам доведеться випробувати більше, ніж просто мод 2 на відмінності, як приклад [1,2,5,11,17]є канонічним. Можливо, подивіться на папір, пов’язаний у моїй відповіді.
Джонатан Аллан

... і просто підтвердити це кодом гордості haskeller, а не моїм: ideone.com/C022x0
Джонатан Аллан

@WheatWizard є [1,2,5,11,17] правдою чи помилкою?
Йорг Гюльсерманн

4

JavaScript (ES6), 116 125 130

l=>eval("r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;for(x=l[0]*2;--x>1;r(x,g))g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));x")

Для цього потрібен вхідний масив відсортований у порядку зменшення. Для кожного значення від 2N до центру 2 (N - максимальне значення монети), він знайде кількість монет із жадного алгоритму та спробує знайти менший набір монет.

Менше гольфу

l=>{
  // recursive function to to find a smaller set of coins
  // parameter k is the max coin limit
  r = (d,k) => d // check if difference is not 0
     ? --k // if not, and if the number of coins used will be less than limit
      && l.map(v => v>d || r(d-v, k))  // proceed with the recursive search
     : x=1 // if diff is 0, value found, set x to 1 to stop the loop
  for( x=l[0]*2; --x > 1; )  
    g=0, h=x, l.map(v=>(g += h/v|0, h %= v)), // find g with the greedy algorithm
    r(x,g) // call with initial difference equal to target value
  return x
}

Тест

f=
l=>eval("r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;for(x=l[0]*2;--x>1;r(x,g))g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));x")

/* No eval
f=l=>{
  r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;
  for(x=l[0]*2;--x>1;r(x,g))
    g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));
  return x;
}*/

;[
 [[100,50,20,10,5,2,1],1], [[4,3,1],0],
 [[25,10,5,1],1], [[25,10,6,1],0],
 [[3,2,1],1], [[30,17,8,1], 0], 
 [[12,8,3,1],0], [[13,8,2,1], 0]
].forEach(t=>{
  var i=t[0],k=t[1],r=f(i),
      msg=((r==k)?'OK ':'KO ')+i+' -> '+r
      + (r==k?'':' (should be '+k+')')
  O.textContent += msg+'\n'
})

function test()
{
  var i=I.value.match(/\d+/g).map(x=>+x).sort((a,b)=>b-a)
  O.textContent = i+' -> '+f(i)+'\n'+O.textContent
 }
#I { width:50% }
<input id=I value='1 4 9'><button onclick='test()'>test</button>
<pre id=O></pre>


4

Пітон, 218 211 205 байт

-1 байт завдяки @TuukkaX (пробіл можна видалити між <3та or)

from itertools import*
g=lambda x,c,n=0:x and g(x-[v for v in c if v<=x][0],c,n+1)or n
lambda c:len(c)<3or 1-any(any(any(x==sum(p)for p in combinations(c*i,i))for i in range(g(x,c)))for x in range(c[0]*2))

repl.it

Введіть у порядку зменшення.

Жахливо жорстока сила. Будь-який набір одиничної монети та якоїсь іншої монети є канонічним. Для більших наборів найменший випадок відмови, якщо одна з існуючих буде більшою або дорівнює 3-й найменшій монеті (не впевнений у собі, як вона могла бути рівна!) Та меншою за суму двох найбільших монет - дивіться у цьому документі (що насправді посилається на інший, але також дає метод O (n ^ 3).

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

gпрацює, виконуючи те , що касир буде, вона рекурсивно займає найбільшу монету менше або дорівнює сумі , по- , як і раніше , щоб компенсувати , [v for v in c if v<=x][0]геть, і підраховує кількість монет , які використовуються n.

Безіменна функція повертає 1, якщо len(c)менше 3, і в іншому випадку перевіряє, що це не так, 1-...що будь-які значення в діапазоні можливостей range(c[0]*2)))можливі з меншими монетами, i in range(g(x,c))зробивши колекцію такої кількості кожної монети, c*iта вивчаючи всі комбінації iмонет, combinations(c*i,i)щоб побачити, чи є якась сума, що має однакове значення.


@WheatWizard повертає False for [13,8,2,1] - я додав його до тестових випадків. Додано уточнення, що введення йде у порядку зменшення.
Джонатан Аллан

1
3orповинні працювати.
Yytsi

Завдяки @TuukkaX, і я міг би замінити not(...)з1-...
Джонатан Allan

2

Желе ( виделка ), 15 14 байт

SRæFµS€Ṃ=$Ṫµ€Ȧ

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

Ця програма обчислює всі тестові випадки менше ніж на секунду на моїй машині.

На жаль, це спирається на гілку Jelly, де я працював над впровадженням атома Frobenius для вирішення, тому ви не можете спробувати його в Інтернеті.

Використання

$ ./jelly eun 'SRæFµS€Ṃ=$Ṫµ€Ȧ' '1,2,4,6,8'
1

Продуктивність хороша і може вирішити всі тестові випадки одразу менше ніж за секунду.

$ time ./jelly eun 'SRæFµS€Ṃ=$Ṫµ€Ȧ¶Ç€' '[[1,3,4],[1,5,10,25],[1,6,10,25],[1,2,3],[1,8,17,30],[1,3,8,12],[1,2,8,13],[1,2,4,6,8]]'
[0, 1, 0, 1, 0, 0, 0, 1]

real    0m0.793s
user    0m0.748s
sys     0m0.045s

Пояснення

SRæFµS€Ṃ=$Ṫµ€Ȧ  Input: list of integers C
    µ           Start a new monadic chain
S                 Sum
 R                Range, [1, 2, ..., sum(C)]
  æF              Frobenius solve for each X in the range using coefficients from C
                  This generates all vectors where the dot product of a
                  vector with C equals X, ordered by using values from the
                  start to end of C
           µ€   Start a new monadic chain that operates on each list of vectors
     S€           Sum each vector
         $        Monadic hook on the sums
       Ṃ            Minimum (This is the optimal solution)
        =           Vectorized equals, 1 if true else 0
          Ṫ       Tail (This is at the index of the greedy solution)
             Ȧ  All, returns 0 if it contains a falsey value, else 1

2

JavaScript (ES6), 144 132 124 122 110 байт

a=>![...Array(a[0]*2)].some((_,i)=>(g=(a,l=0,n=i)=>[a.filter(c=>c>n||(l+=n/c|0,n%=c,0)),-l*!n])(...g(a))[1]>0)

Потрібен сортування масиву у порядку зменшення. Використовується спостереження у зв'язаному документі, що якщо система не є канонічною, то принаймні на одне значення менше 2a [0], що займає менше монет при їх розкладанні за допомогою невикористаних монет з початкового жадібного алгоритму.

Редагувати: Збережено 12 байт, зрозумівши, що я можу перевірити всі монети, хоча я вже досяг цільового значення. Збережено 8 байт шляхом переключення проміжного виводу з [l,b]на [b,-l]; це дозволило мені передати перший результат безпосередньо як параметр другого виклику, а також невелике збереження, яке визначає, чи вдалий був другий виклик. Збережено 2 байти, перемістивши визначення gу someзворотний виклик, що дозволяє мені уникнути зайвого переходу в змінну циклу двічі. Збережено 12 байт, перейшовши з моєї рекурсивної функції помічника на виклик filter(це стало можливим моїм проміжним вимикачем).


2

Perl, 69 байт

Включає +2 для -pa

Дайте монети у порядку зменшення на STDIN. Можливо, ви можете залишити 1монету.

coins.pl <<< "4 3 1"

coins.pl:

#!/usr/bin/perl -pa
$_=!map{grep$`>=$_&&($n=$G[$`-$_]+1)<($G[$`]||=$n),@F,/$/}1..2*"@F"

Нараховує кількість монет, використаних алгоритмом касирів, @Gна суми від 1 до 2 разів найбільші монети. Для кожної суми перевіряється, що якщо ця сума зменшиться на 1 монету, алгоритму касира потрібно не менше 1 монети менше. Якщо ні, то це контрприклад (або раніше був контрприклад). Я міг зупинитися на першому контрприкладі, але це займає більше байтів. Отже, складність у часі є, O(max_coin * coins)а космічна - складністьO(max_coin)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.