Экономьте деньги с округлением цены


18

В Канаде копейки больше не распространяются. Наличные платежи округляются до ближайших 5 центов.

Деньги можно сэкономить, разделив покупки. Например, два предмета по 1,02 долл. США стоят 2,04 долл., Что округляет до 2,05 долл., Но при покупке предметов по отдельности каждая цена округляется до 1,00 долл., Что в сумме составляет 2,00 долл. США. Однако при покупке двух предметов по 1,03 долл. Каждый лучше покупать их за одну покупку.

Еще один способ сэкономить деньги - использовать кредитную карту, когда округление является неблагоприятным, поскольку платежи по кредитам не округляются. Если мы хотим получить два товара по 1,04 доллара, общая цена будет округлена до 2,10 доллара независимо от того, как мы разделили покупки. Поэтому мы должны оплатить эти товары с помощью кредитной карты.

Напишите функцию или программу, которая принимает список цен товаров в виде целых чисел в центах и ​​выводит наименьшую возможную общую цену (в центах) для тех товаров, которая может быть достигнута с помощью последовательности покупок, каждая из которых является либо наличными, либо кредитом.

Самый короткий код выигрывает.

Контрольные примеры

[] : 0
[48] : 48
[92, 20] : 110
[47, 56, 45] : 145
[55, 6, 98, 69] : 225
[6, 39, 85, 84, 7] : 218
[95, 14, 28, 49, 41, 39] : 263
[92, 6, 28, 30, 39, 93, 53] : 335
[83, 33, 62, 12, 34, 29, 18, 12] : 273
[23, 46, 54, 69, 64, 73, 58, 92, 26] : 495
[19, 56, 84, 23, 20, 53, 96, 92, 91, 58] : 583
[3, 3, 19, 56, 3, 84, 3, 23, 20, 53, 96, 92, 91, 58, 3, 3] : 598
[2, 3, 4, 4, 4, 4, 4] : 19

Ответы:


5

Рубин, 119 105 символов (93 тела)

def f s
a,b,c,d=(1..4).map{|i|s.count{|x|x%5==i}}
s.reduce(0,:+)-a-(c-m=c>d ?d:c)/2-2*(b+m+(d-m)/3)
end

Два символа могут быть сохранены, если алгоритм допускает сбой при подаче пустого списка покупок.


Вы можете изменить на s.reduce(:+)(обычно вам даже не нужны паратезы, но в вашем случае ...) и встроить mдополнительные 2 символа.
Говард

И конечно a,b,c,d=(1..4).map{|i|s.count{|x|x%5==i}}.
Говард

@ Говорят, если я удалю 0,из reduceвызова, код обрывается для пустого ввода. Я упомянул это в ответе. Встраивание m, кажется, не помогает. Спасибо за последнее предложение - это было глупо с моей стороны.
Джон Дворжак

1
Вы можете написать, (c-m=c>d ?d:c)что дает вам два символа.
Говард

@Howard Я думал, что это сломается, потому что -имеет более высокий приоритет, чем =. Это то, что присвоение имеет высокий приоритет на левой стороне (например, чтобы убедиться, что левый операнд является lvalue)?
Джон Дворжак

5

GolfScript (54 символа)

~]4,{){\5%=}+1$\,,}%~.2$>$:m- 3/m+@+2*@@m- 2/++~)+{+}*

Это программа, которая принимает входные данные из stdin в качестве разделенных пробелами значений. Один символ может быть сохранен, если вместо этого ввести формат ввода в виде массивов GolfScript.

Тестовые случаи онлайн

Самый интересный трюк .2$>$для неразрушающего minоператора.


Мой анализ математики по сути такой же, как и анализ Яна и Рэя: учитывая значения мод 5, единственная экономия на транзакциях стоимостью 1 или 2. Опция кредитной карты означает, что мы никогда не сходимся. Таким образом, предмет, который стоит 5n + 2 цента, не может выиграть от связывания; и при этом предмет не может стоить 5n + 1 центов (потому что объединение двух 1-центовых сбережений в 2-центовые сбережения не дает никакой выгоды). 0 - аддитивная тождественность, поэтому единственные интересные случаи включают значения 3 и 4. 3+3 = 1и 3+4 = 4+4+4 = 2; если у нас есть смешанные 3s и 4s , то мы оптимизируем предпочитая 3+4более 3+3(строго лучше) или 4+4+4(эквивалент).


+1 - хотя эти пробелы выглядят так щедро ;-) Вы можете удалить их, сохранив -m ( ~):m), к сожалению, без уменьшения количества символов.
Говард

@ Говард, я тоже пробовал. : D
Питер Тейлор

3

C ++: 126 символов

int P(int*m,int i){int t=0,h=0,d;while(i>-1){d=m[i]%5;t+=m[i--];d<3?t-=d:d==4?h++,t-=2:h--;}h<0?t+=h/2:t+=(h-h/3)*2;return t;}

Добро пожаловать, чтобы дать руководство, чтобы эта программа стала короче. Вот тестовая программа, скомпилируйте с помощью компилятора tdm-gcc 4.7.1 и работайте нормально.

#include<iostream>
using namespace std;

//m[i]表示单个商品的价格,t表示所有商品总价格,
//d为单个商品价格取模后的值,h为单个商品价格取模后值为3的个数,
//f为单个商品价格取模后值为4的个数
int P(int*m,int i){int t=0,h=0,d;while(i>-1){d=m[i]%5;t+=m[i--];d<3?t-=d:d==4?h++,t-=2:h--;}h<0?t+=h/2:t+=(h-h/3)*2;return t;}

int main() {
int p1[1]={48};
int p2[2]={92,20};
int p3[3]={47,56,45};
int p4[4]={55,6,98,69};
int p5[5]={6,39,85,84,7};
int p6[6]={95,14,28,49,41,39};
int p7[7]={92,6,28,30,39,93,53};
int p8[8]={83,33,62,12,34,29,18,12};
int p9[9]={23,46,54,69,64,73,58,92,26};
int p10[10]={19,56,84,23,20,53,96,92,91,58};
int p11[10]={1,2,3,4,5,6,7,8,9,10};
cout<<P(p1,0)<<endl
    <<P(p2,1)<<endl
    <<P(p3,2)<<endl
    <<P(p4,3)<<endl
    <<P(p5,4)<<endl
    <<P(p6,5)<<endl
    <<P(p7,6)<<endl
    <<P(p8,7)<<endl
    <<P(p9,8)<<endl
    <<P(p10,9)<<endl
    <<P(p11,9)<<endl;

return 0;
}

1

R 143

function(x)min(sapply(rapply(partitions::listParts(length(x)),
                             function(i)min(sum(x[i]),5*round(sum(x[i])/5)),h="l"),
                      function(x)sum(unlist(x))))

Тесты (где Pпсевдоним для кода выше)

> P(c(48))
[1] 48
> P(c(92, 20))
[1] 110
> P(c(47, 56, 45))
[1] 145
> P(c(55, 6, 98, 69))
[1] 225
> P(c(6, 39, 85, 84, 7))
[1] 218
> P(c(95, 14, 28, 49, 41, 39))
[1] 263
> P(c(92, 6, 28, 30, 39, 93, 53))
[1] 335
> P(c(83, 33, 62, 12, 34, 29, 18, 12))
[1] 273
> P(c(23, 46, 54, 69, 64, 73, 58, 92, 26))
[1] 495
> P(c(19, 56, 84, 23, 20, 53, 96, 92, 91, 58))
[1] 583

1

Mathematica 112 126 167 157

Изменить : Случаи {3, 3} и {4,4,4} теперь обрабатываются благодаря Питеру Тейлору и картонному ящику.

n_~g~o_ := {a___, Sequence @@ n, b___} :> {a, b, o};
f@s_ := Tr@Join[#[[2]], Sort@#[[1]] //. {1 -> 0, 2 -> 0, g[{3, 4}, 5], g[{3, 3}, 5], 
   g[{4, 4, 4}, 10]}] &[Transpose[{m = Mod[#, 5], # - m} & /@ s]]

Примечание. Номера для покупок (контрольный пример № 1) вводятся как f[{0}].

Как это устроено

  1. За каждую единицу будет выплачено наибольшее значение, кратное 5, меньше соответствующей цены, независимо от формы оплаты. (Не обойтись.)
  2. Остатки Mod[n, 5]затем обрабатываются: 1 и 2 становятся 0. Нули остаются неизменными.
  3. Каждая пара {3, 4} -> {5}; после каждой пары {3, 3} -> {5}; затем тройка, {4,4,4} -> {10}, если применимо.
  4. Остальные 4, если таковые имеются, остаются без изменений (оплачивается кредитной картой).
  5. Исходные значения, кратные 5, суммируются с остатками, которые были изменены (или нет) на этапах (2) - (4).

тестирование

a12настраивается на {3,3} a13регулируется на {4,4,4}

a1={0};
a2={48};
a3={92,20};
a4={47,56,45};
a5={55,6,98,69} ;
a6={6,39,85,84,7};
a7={95,14,28,49,41,39};
a8={92,6,28,30,39,93,53};
a9={83,33,62,12,34,29,18,12};
a10={23,46,54,69,64,73,58,92,26};
a11={19,56,84,23,20,53,96,92,91,58};
a12={3,3,19,56,3,84,3,23,20,53,96,92,91,58,3,3};
a13={2,3,4,4,4,4,4};

f /@ {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13}

{0, 48, 110, 145, 225, 218, 263, 335, 273, 495, 583, 598, 19}


1
А как насчет {3,3}?
Питер Тейлор

@PeterTaylor. Хорошая точка зрения. Это ускользнуло.
DavidC

Как насчет {4,4,4}? Я думаю, с {3,4} -> {5}, {3,3} -> {5} и {4,4,4} -> {10} (в таком порядке) он должен дать оптимальные ответы.
картонная

@cardboard_box Вы правы! Смотрите обновление.
DavidC

Я добавил ваши дополнительные тестовые примеры к вопросу. Те, что были у меня, были сгенерированы случайным образом, поэтому эти угловые случаи не обнаружились
картонная

1

Python 3 (115 символов)

m=eval(input());t=a=b=0
for v in m:d=v%5;t+=v-d*(d<3);a+=d==3;b+=d==4
d=min(a,b);a-=d;b-=d;print(t-d*2-a//2-b//3*2)

Python 2 (106 символов)

m=input();t=a=b=0
for v in m:d=v%5;t+=v-d*(d<3);a+=d==3;b+=d==4
d=min(a,b);a-=d;b-=d;print t-d*2-a/2-b/3*2

2
Вопрос требует итоговой цены, поэтому для всего списка должен быть один вывод. Например, ввод [3,4,9]должен дать 14, потому что вы можете объединить элементы 3 и 4 цента, чтобы получить 7-центовую покупку, которую вы платите наличными с 5 центами, а оставшуюся 9-центовую вещь вы заплатите в кредит, потому что в противном случае она округлилась бы в большую сторону.
картонная

2
Учитывая 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, это дает 0.0, 0.0, 2.5, 3.33, 5.0, 5.0, 5.0, 7.5, 8.33, 10.0, что суммы 46.66. Тем не менее, правильный ответ таков 45, поэтому сумма чисел, которые вы печатаете, не является правильным ответом, и, следовательно, это решение неверно.
Nolen Royalty

Этот ответ был записан, когда задание еще не содержит «итого»
AMK

2
Боюсь, я должен рекомендовать удаление. Аскер не изменил требования - он уточнил их. Если цена для каждого товара в отдельности была желательной, то почему упоминание о «последовательности покупок / единичных покупок» и обсуждение того, какой из них выгоден?
Джон Дворак

Я удаляю неправильные ответы. Теперь это самые короткие ответы Python
AMK

0

APL, 58 символов

{a b c d←+/(⍳4)∘.=5|⍵⋄(+/⍵)-a-(⌊2÷⍨c-m)-2×b+m+⌊3÷⍨d-m←c⌊d}

Программа по сути является прямым переводом Ruby от Jan Dvorak .


      {a b c d←+/(⍳4)∘.=5|⍵⋄(+/⍵)-a-(⌊2÷⍨c-m)-2×b+m+⌊3÷⍨d-m←c⌊d}⍬
0
      {a b c d←+/(⍳4)∘.=5|⍵⋄(+/⍵)-a-(⌊2÷⍨c-m)-2×b+m+⌊3÷⍨d-m←c⌊d}95 14 28 49 41 39
263
      {a b c d←+/(⍳4)∘.=5|⍵⋄(+/⍵)-a-(⌊2÷⍨c-m)-2×b+m+⌊3÷⍨d-m←c⌊d}19 56 84 23 20 53 96 92 91 58
583

это пустой вектор.


0

Юлия 83C

C=L->let
w,z,x,y=map(i->[i==x%5for x=L]|sum,1:4)
L|sum-(x+2w+3min(x,y)+4z)>>1
end

Explaination:

За одну покупку вы можете сэкономить не более 2 центов. Так что если у вас есть комбинация, которая может сэкономить вам 2 цента, просто купите ее таким образом, и она будет оптимальной . Например, если у вас есть xпредметы с ценой 3 (мод 5) и yпредметы с ценой 4 (мод 5), вы можете сделать min(x, y)количество (3, 4) пар, что сэкономит ваши 2 min(x, y)центы. Затем вы используете остальные 3, если таковые имеются, чтобы сэкономить ваши max(0, x-min(x,y)) / 2центы. Это также может быть рассчитано по(max(x,y)-y)/2

w = sum(1 for p in prices if p % 5 == 1)
z = sum(1 for p in prices if p % 5 == 2)
x = sum(1 for p in prices if p % 5 == 3)
y = sum(1 for p in prices if p % 5 == 4)

ans = sum(prices) - (w + 2 z + 2 min(x, y) + div(max(x, y) - y, 2))
    = sum(prices) - (2w + 4z + 4 min(x, y) + x + y - min(x, y) - y) `div` 2
    = sum(prices) - (2w + 4z + 3 min(x, y) + x) `div` 2

редактировать

Это решение неверно.


+1 за использование относительно неизвестного языка, который может быть интересно выучить
Джон Дворжак

Это новый язык в стадии активного развития. Он сочетает в себе много силы из разных языков. Надеюсь, что больше людей могут знать это.
Рэй

Анализ не совсем завершен, потому что если у вас есть, 4 4 4 3 3то 4 4 4есть комбинация, которая может сэкономить 2 цента, но ее покупка не является оптимальной. (На самом деле, вы, похоже, вообще не принимаете 4 4 4во внимание. Разве этот код не проходит последний тестовый случай?)
Питер Тейлор
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.