Допоможіть мені носити сумки


26

Це був теплий літній вечір ...

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

Шлях до центру міста

Ваша мета

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

ВАГАЛЬНА ЛІВА Рука - ВАГА ПРАВА РУКА ≈ 0

Приклад

Якщо у мене було лише 2 предмети, хліб та арахісове масло, а маса хліба - 250 грам, а арахісове масло - 150 грам, найкращий спосіб - носити їх окремо двома руками.

W LH - W RH = W (ХЛІБ) - W (P.BUTTER)
250 - 150 = 100

Інша можливість:

W (ХЛІБ, P.BUTTER) - W (порожня рука) = (250 + 150) - 0 = 400

Це не краще, ніж наш перший випадок, тому вам слід піти з першим.

Ваш код повинен

  1. взяти введення цифр із зазначенням ваги предметів у сумці для покупок. Одиниці не важливі, але вони повинні бути однаковими (в ідеалі кілограмами або грамами). Введення можна зробити по одному або всім відразу. Ви можете обмежити загальну кількість до 20 предметів, якщо ви хочете.
  2. Формат / тип введення вирішувати вам, але нічого іншого, крім ваг, не повинно бути.
  3. Будь-яка мова дозволена, але дотримуйтесь стандартних бібліотек.
  4. Дисплейний вихід. Знову ж таки, ви можете вибрати формат, але поясніть формат у своїй публікації. тобто як ми можемо визначити, які з них є предметами лівої руки, а які - предметами правої руки.

Очки

  1. Найкоротший код виграє.

Підказка

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


5
Мені подобається правило 2, воно гнучко, але не дозволяє обманювати
edc65

2
Ви в основному винаходили проблему рюкзака. en.wikipedia.org/wiki/Knapsack_problem
Sparr

Дякую @Sparr Я злий smaat (не дуже)
Renae Lider

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

Відповіді:


15

Pyth, 9 байт

ehc2osNyQ

Формати введення, виведення:

Input:
[1, 2, 3, 4, 5]
Output:
[1, 2, 4]

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

ehc2osNyQ
             Q = eval(input())
       yQ    Take all subsets of Q.
    osN      Order those element lists by their sums.
  c2         Cut the list in half.
eh           Take the last element of the first half.

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


Відповідь ОП роздруковує лише мішки в одній руці, тому вітаю з вашим 9-байтним рішенням.
Денніс

Ваше запитання помиляється на вході [7 7 7 10 11] Відстеження (останній дзвінок останній): Файл "pyth.py", рядок 772, у <module> Файл "<string>", рядок 4, у <module> Файл "/app/macros.py", рядок 865, для типу TypeError: unordevable types: int () <list ()
RosLuP

@RosLuP Це працювало в той час, я щось змінив, sщо змусило його перестати працювати. Людям не сподобалася зміна, і ваш коментар був останнім поштовхом, який мені потрібно було змінити.
isaacg

У коментованому коді не повинно бути "підмножина Q", а "
підпис

@RosLuP Я не погоджуюсь - підпис зазвичай є суміжним. Підмножина та послідовність - це два терміни для такого роду речі.
isaacg

6

Піта, 16

ho.a-FsMNs./M.pQ

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

Спробуйте його онлайн тут

Щоб підтримувати обробку лише одного входу, це до 17:

hho.a-FsMNs./M.pQ

Це надрукує значення, які йдуть в одну руку.


Це дуже вражаюче рішення - зовсім не очевидно, що воно не дасть помилкових відповідей на кшталт [[2], [1], [1]], але я думаю, що це працює завдяки тому, як саме ./працює.
isaacg

Насправді, я думаю, це не вдається у випадках, коли все йде однією рукою, наприклад, коли є лише 1 об’єкт.
isaacg

@isaacg Я вважав, що 1 об’єкт недійсний, оскільки ви, очевидно, повинні були просто тримати його в одній руці. Я б насправді не знав, що за це повернути [[x], []]?
FryAmTheEggman

Я думаю, що так - це, мабуть, нормально, якщо ОП не каже іншого.
isaacg

@isaacg Я опублікував відповідь нижче. Він дає правильну відповідь за 1 елемент (мені довелося додати ще один байт до коду)
Renae Lider,

6

CJam, 19 18 байт

{S+m!{S/1fb:*}$W=}

Це анонімна функція, яка вискакує масив цілих чисел із стека та повертає масив цілих чисел, розділених пробілом.

Завдяки @ jimmy23013 за його геніальний :*трюк, який врятував 1 байт.

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

S+    e# Append a space to the array of integers.
m!    e# Push the array of all possible permutations.
{     e# Sort the array by the following:
  S/  e#   Split the array at the space.
  1fb e#   Add the integers in each chunk (using base 1 conversion).
  :*  e#   Push the product of both sums.
}$    e# Permutations with a higher product will come last.
W=    e# Select the last permutation.

Позначимо загальна вага сумок з W . Потім, якщо мішки в одній з рук важать W / 2 - D / 2 , ті, що знаходяться в іншій руці, повинні важити, а W - (W / 2 - D / 2) = W / 2 + D / 2 .

Ми намагаємося звести до мінімуму різницю D . Але (W / 2 - D / 2) (W / 2 + D / 2) = W ^ 2/4 - D ^ 2/4 , який стає більшим, коли D стає меншим.

Таким чином, максимальний продукт відповідає мінімальній різниці.


Я думаю :*... W=повинен працювати.
jimmy23013

@ jimmy23013: Дякую! Це зробило мою відповідь набагато цікавішою.
Денніс

5

Пітон 2.7, 161 , 160

код

from itertools import*
m=input();h=sum(m)/2.;d=h
for r in(c for o in range(len(m)+1) for c in combinations(m,o)):
 t=abs(h-sum(r))
 if t<=d:d=t;a=r
print a

Алгоритм

2 х W одна рука = Загальна вага
W одна рука ~ Загальна вага / 2

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

вхід

>>>[1,2,3,4]

вихід

(2, 3)

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


Ви можете зберегти один байт, зробивши цеfrom itertools import*
DJMcMayhem

4

JavaScript ( ES6 ) 117

Використовуючи трохи маски, щоб спробувати всі можливі розбиття, тому вона обмежена 31 предметом (нормально з правилами). Як і відповідь на відповідь, вона видає лише одну руку. Примітка: я шукаю мінімальну різницю> = 0, щоб уникнути Math.abs, оскільки для кожного хв <0 є ще один> 0, просто міняючи руками.

Щоб перевірити: запустіть фрагмент у Firefox, введіть список номерів, кома чи пробіл.

f=(l,n)=>{ // the unused parameter n is inited to 'undefined'
  for(i=0;++i<1<<l.length;t<0|t>=n||(r=a,n=t))
    l.map(v=>(t+=i&m?(a.push(v),v):-v,m+=m),m=1,t=0,a=[]);
  alert(r)
}

// Test

// Redefine alert to avoid that annoying popup when testing
alert=x=>O.innerHTML+=x+'\n';

go=_=>{
  var list=I.value.match(/\d+/g).map(x=>+x); // get input and convert to numbers
  O.innerHTML += list+' -> ';
  f(list);
}
#I { width: 300px }
<input id=I value='7 7 7 10 11'><button onclick='go()'>-></button>

<pre id=O></pre>


2

Haskell, 73 байти

import Data.List
f l=snd$minimum[(abs$sum l-2*sum s,s)|s<-subsequences l]

Виводить список предметів однією рукою. Відсутні елементи переходять до іншого боку.

Використання: f [7,7,7,10,11]->[7,7,7]

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


1

Haskell, 51 байт

f l=snd$minimum$((,)=<<abs.sum)<$>mapM(\x->[x,-x])l

Формат вихідного сигналу полягає в тому, що ліві ваги є позитивними, а права - негативними.

>> f [2,1,5,4,7]
[-2,-1,5,4,-7]

Щоб генерувати кожен можливий розкол, ми використовуємо mapM(\x->[x,-x])lдля заперечення кожного можливого підмножини елементів. Потім ((,)=<<abs.sum)позначте кожну свою абсолютну суму і snd$minimum$((,)=<<abs.sum)візьміть найменший розмічений елемент.

Я не міг зрозуміти це без проблем через проблеми перевірки типу.


@WillNess Вони всі в прелюдії в поточній версії.
xnor

ДО РЕЧІ наступний пункт вільної код працює на GHCi карта: snd.minimum.map((,)=<<abs.sum).mapM(\x->[x,-x]). Це 47 байт. (хоча у мене встановлена ​​старіша версія ...)
Буде Нісс

0

R (234)

довше і повільніше рішення з Р.

Функція:

function(p){m=sum(p)/2;n=100;L=length(p);a=matrix(0,n,L+2);for(i in 1:n){idx=sample(1:L,L);a[i,1:L]=idx;j=1;while(sum(p[idx[1:j]])<=m){a[i,L+1]=abs(sum(p[idx[1:j]])-m);a[i,L+2]=j;j=j+1}};b=which.min(a[,L+1]);print(p[a[b,1:a[b,L+2]]])}


Очікуваний вхід - вектор з вагами.
Очікуваний вихід - вектор з вагами для однієї руки.


Приклад

> Weight(c(1,2,3,4))
[1] 3 2
> Weight(c(10,1,2,3,4))
[1] 10
> Weight(c(40,20,80,50,100,33,2))
[1] 100  40  20  2
> Weight(c(7,7,7,10,11))
[1] 7 7 7

Версія для коду, що читається людиною:

weight <- function(input) {
  mid <- sum(input)/2
  n <- 100
  input_Length <- length(input)
  answers <- matrix(0, n, input_Length+2)
  for(i in 1:n){
    idx <- sample(1:input_Length, input_Length)
    answers[i, 1:input_Length ] <- idx
    j <- 1
    while(sum(input[idx[1:j]]) <= mid){
        answers[i, input_Length+1] <- abs(sum(input[idx[1:j]]) - mid)
        answers[i, input_Length+2] <- j
        j <- j + 1
    }
  }
  best_line <- which.min(answers[, input_Length+1])
  print(paste("weight diference: ", answers[best_line, input_Length+1]))
  print(input[answers[best_line, 1:answers[best_line, input_Length+2]]])
}

0

Аксіома, 292 байти

R==>reduce;F(b,c)==>for i in 1..#b repeat c;p(a)==(#a=0=>[a];w:=a.1;s:=p delete(a,1);v:=copy s;F(s,s.i:=concat([w],s.i));concat(v,s));m(a)==(#a=0=>[[0],a];#a=1=>[a,a];b:=p(a);r:=[a.1];v:=R(+,a)quo 2;m:=abs(v-a.1);F(b,(b.i=[]=>1;d:=abs(v-R(+,b.i));d<m=>(m:=d;r:=copy b.i);m=0=>break));[[m],r])

Застосування жорстокої сили. Це мінімізувало б набір

A={abs(reduce(+,a)quo 2-reduce(+,x))|x in powerSet(a)}

бо якщо мінімальний

y=min(A)=abs(reduce(+,a)quo 2-reduce(+,r))

це також було б мінімальним

2*y=abs(reduce(+,a)-2*reduce(+,r))=abs((reduce(+,a)-reduce(+,r))-reduce(+,r)) 

де (зменшити (+, a) - зменшити (+, r)) і зменшити (+, r) - це 2 ваги двох мішків. (Але ця остання формула не знаходить для мене мінімуму в додатку). Ungolf та результати

-- Return the PowerSet or the Powerlist of a
powerSet(a)==
    #a=0=>[a]
    p:=a.1;s:=powerSet delete(a,1);v:=copy s
    for i in 1..#s repeat s.i:=concat([p],s.i)
    concat(v,s)

-- Return one [[m], r] where
-- r is one set or list with reduce(+,r)=min{abs(reduce(+,a)quo 2-reudece(+,x))|x in powerSet(a)}
-- and m=abs(reduce(+,a) quo 2-reduce(+,r))
-- because each of two part, has to have the same weight
MinDiff(a)==
    #a=0=>[[0],a]
    #a=1=>[ a ,a]
    b:=powerSet(a)
    r:=[a.1];v:=reduce(+,a) quo 2;m:=abs(v-a.1)
    for i in 1..#b repeat
        b.i=[]=>1
        k:=reduce(+,b.i)
        d:=abs(v-k)
        d<m=>(m:=d;r:=copy b.i)
        m=0=>break
    [[m],r]

--Lista random di n elmenti, casuali compresi tra "a" e "b"
randList(n:PI,a:INT,b:INT):List INT==
    r:List INT:=[]
    a>b =>r
    d:=1+b-a
    for i in 1..n repeat
          r:=concat(r,a+random(d)$INT)
    r

(5) -> a:=randList(12,1,10000)
   (5)  [8723,1014,2085,5498,2855,1121,9834,326,7416,6025,4852,7905]
                                                       Type: List Integer
(6) -> m(a)
   (6)  [[1],[1014,2085,5498,1121,326,6025,4852,7905]]
                                                  Type: List List Integer
(7) -> x:=reduce(+,m(a).2);[x,reduce(+,a)-x]
   (7)  [28826,28828]
                                               Type: List PositiveInteger
(8) -> m([1,2,3,4])
   (8)  [[0],[2,3]]
                                                  Type: List List Integer
(9) -> m([10,1,2,3,4])
   (9)  [[0],[10]]
                                                  Type: List List Integer
(10) -> m([40,20,80,50,100,33,2])
   (10)  [[0],[40,20,100,2]]
                                                  Type: List List Integer
(11) -> m([7,7,7,10,11])
   (11)  [[0],[10,11]]
                                                  Type: List List Integer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.