Економте гроші за допомогою округлення цін


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}}.
Говард

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

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

@Howard Я думав, що це зламається, тому що -має вищий пріоритет, ніж =. Це так, що призначення має високий пріоритет на лівій стороні (як у, щоб переконатися, що лівий операнд є рівним)?
Джон Дворак

5

GolfScript (54 символи)

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

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

Тестові приклади в Інтернеті

Найцікавіший трюк - .2$>$для неруйнівного minоператора.


Мій аналіз математики по суті такий же, як і у Яна та Рея: враховуючи значення mod 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), на жаль, без зменшення кількості знаків.
Говард

@Howard, я знаю, я також спробував це. : 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} зараз вирішуються завдяки Пітеру Тейлору та cardboard_box.

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

@cardboard_box Ви праві! Дивіться оновлення.
DavidC

Я додав ваші додаткові тестові випадки до питання. Ті, що у мене були, генеруються випадковим чином, щоб ті кутові випадки не з’являлися.
cardboard_box

1

Пітон 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)

Пітон 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 цент, ви сплачуєте кредитом, оскільки в іншому випадку вона закрутиться.
cardboard_box

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 Яна Дворака .


      {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

Юлія 83С

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

Пояснення:

За одну покупку ви можете зекономити не більше 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.