Alışveriş çantamı taşımama yardım et


26

Sıcak bir yaz gecesiydi ...

aptal arabam yolumun ortasında süpermarketten dönerken yolun ortasında parçalanmaya karar verdiğinde. Onu kenara itmiştim ve eve yürümeye karar verdim. Alışverişe çıkmak ve kalan şeyleri almak için bagajı açtım. Öyleyse öğelerin eşit şekilde torbalanmadığını fark ettim. Bazı çantalarda daha ağır malzemeler varken, diğerlerinde daha az hafif eşyalar vardı, hatta bazılarında bu tür eşyalar bile vardı. Taşınmamı kolaylaştırmak için her şeyi iki çantaya ayırmaya ve ağırlıklarını birbirine mümkün olduğunca yaklaştırmaya karar verdim.

Şehir yoluma gitmek

Senin hedefin

her iki çanta arasındaki farkın sıfıra yakın olacağı şekilde, ürünleri iki alışveriş torbasına yeniden düzenlememe yardım etmektir.
Matematiksel olarak:

AĞIRLIK SOL EL - AĞIRLIK SAĞLI EL ≈ 0

Örnek

Sadece 2 öğem olsaydı, Ekmek ve Fıstık ezmesi ve ekmeğin ağırlığı 250 gram, yerfıstığı yağı 150 gram ise, en iyi yol onları iki elimizde ayrı taşımaktır.

W LH - W RH W = (EKMEK) - W (P.BUTTER)
250-150 = 100

Diğer olasılık ise:

W (EKMEK, P.BUTTER) - W (boş el) = (250 + 150) - 0 = 400

Bu bizim ilk davamızdan daha iyi değil, o yüzden birincisine gitmelisin.

Kodunuz

  1. Alışveriş çantasındaki eşyaların ağırlığını belirten sayıların girişini yapın. Birimler önemli değildir, ancak aynı olmalıdırlar (ideal olarak kilogram veya gram). Giriş, bir kerede bir veya bir defada yapılabilir. İsterseniz toplam sayımı maksimum 20 madde ile sınırlayabilirsiniz.
  2. Girdi biçimini / türünü seçmek size kalmış, ancak ağırlıklardan başka hiçbir şey bulunmamalıdır.
  3. Her dile izin verilir, ancak standart kitaplıklara sadık kalın.
  4. Görüntü çıkışı. Yine, formatı seçmekte özgürsünüz, ancak yazınızdaki formatı açıklayın. yani hangilerinin sol el, hangilerinin sağ el olduğunu nasıl söyleyebiliriz.

makas

  1. En kısa kod kazanır.

İpucu

Aklıma gelen iki algoritma farklılaşma (daha hızlı) ve permütasyonlar / kombinasyonlar (daha yavaş). Bunları veya işi yapan başka bir algoritmayı kullanabilirsiniz.


5
Kural 2'yi severim, esnektir ancak aldatmaya izin vermez
edc65

2
Temel olarak sırt çantası problemini yeniden keşfettiniz. en.wikipedia.org/wiki/Knapsack_problem
Sparr,

Thank you @Sparr Ben kötü smaat (gerçekten değil)
Renae Lider

2
Bu sorun bu site için çok pratik ve gerçekçi.
Reinstate Monica iamnotmaynard

Yanıtlar:


15

Pyth, 9 bayt

ehc2osNyQ

Giriş, çıkış formatları:

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

Gösteri.

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.

Bu çalışır çünkü yalt kümeleri, her alt kümenin ve onun tamamlayıcısının merkezden eşit uzaklıkta olmasını sağlayacak şekilde döndürür. Bir alt kümenin ve onun tamamlayıcısının toplamı her zaman merkezden eşit olacağından, sonraki liste osNyQde bu özelliğe sahip olacaktır. Bu nedenle, ortadaki iki element osNyQtamamlayıcıdır ve optimal bir bölünmeye sahip olmaları gerekir. Bu iki elementin ilkini çıkarıp basıyoruz.


OP'nin cevabı sadece bir elinde torbaları basar, bu yüzden 9 byte çözümünüz için tebrikler.
Dennis,

Yazmanız giriş için tıkandı [7 7 7 10 11] Geri izleme (en son arama son): Dosya "pyth.py", satır 772, <module> Dosya "<string>", satır 4, <module> Dosya "/app/macros.py", satır 865, TypeError sırayla: düzeltilemez türler: int () <list ()
RosLuP 17:17

@RosLuP Bu zamanda çalıştı, bununla ilgili bir şeyi değiştirdim, sçalışmayı durdurdu. İnsanlar değişiklikten hoşlanmadı ve yorumunuz geri değiştirmek için gereken son baskıydı.
isaacg


@RosLuP Ben katılmıyorum - bir alt liste genellikle bitişiktir. Alt küme ve alt sıra bu tür bir şey için iki terimdir.
isaacg

6

Pyth, 16

ho.a-FsMNs./M.pQ

Bu girişleri STDIN'de bir piton listesi olarak alır. Çıktı, birinci liste bir torbadaki öğeler ve ikinci liste ikinci torbadaki öğeleri temsil eden 2 listenin bir listesidir. Bu kaba komut tüm kombinasyonları zorlar, bu nedenle büyük girdiler için çok yavaş çalışacaktır (veya hafıza tükenecektir).

Burada çevrimiçi deneyin

Sadece bir girişin kullanımını desteklemek için, bu 17'ye kadar çıkar:

hho.a-FsMNs./M.pQ

Bu, bir yandan giden değerleri basacaktır.


Bu çok etkileyici bir çözüm - gibi yanlış cevaplar vermeyeceği açık değil [[2], [1], [1]], ama tam olarak nasıl ./çalıştığından dolayı çalıştığını düşünüyorum .
isaacg

Aslında, bunun sadece 1 nesne olduğu gibi, her şeyin bir elden geçtiği durumlarda başarısız olduğunu düşünüyorum.
isaacg

@isaacg Bir nesnenin sadece bir elinde tutması gerektiği için 1 nesnenin geçerli olmadığını varsaydım. Bunun için ne döneceğini gerçekten bilemem, değil [[x], []]mi?
FryAmTheEggman

Sanırım - OP aksini söylemediği sürece muhtemelen sorun yok.
isaacg

@isaacg Aşağıda bir cevap gönderdim. 1 eleman için doğru cevabı veriyor (koda bir bayt daha eklemek zorunda kaldım)
Renae Lider

6

CJam, 19 18 bayt

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

Bu, yığıntan bir tamsayı dizisi açan ve boşlukla ayrılmış bir tamsayı dizisi döndüren adsız bir işlevdir.

:*1 byte tasarruf sağlayan ustaca numarası için @ jimmy23013'e teşekkürler .

CJam tercümanında çevrimiçi olarak deneyin .

Nasıl çalışır

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.

Alışveriş torbalarının toplam ağırlığını W ile belirtin . Daha sonra, ellerden birindeki torbalar W / 2 - D / 2 ağırlığındaysa, diğer eldeki olanlar ağırlığında ve W - (W / 2 - D / 2) = W / 2 + D / 2 olmalıdır .

D farkını en aza indirmeye çalışıyoruz . Ancak (W / 2 - D / 2) (W / 2 + D / 2) = W ^ 2/4 - D ^ 2/4, D küçüldükçe büyür.

Bu nedenle, azami ürün asgari farka karşılık gelir.


Bence :*... W=çalışmalı.
jimmy23013

@ jimmy23013: Teşekkürler! Bu benim cevabımı çok daha ilginç hale getirdi.
Dennis,

5

Python 2.7, 161 , 160

kod

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

Algoritma

2 x W bir yandan = Toplam ağırlık
W bir yandan ~ Toplam ağırlık / 2

Her kombinasyonun toplam ağırlığın yarısına yaklaşıp yaklaşmadığını kontrol edin. Tekrarlayın ve en iyisini bulun.

giriş

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

çıktı

(2, 3)

Görüntülenen demet bir yandan gider, gösterilmeyen diğerine gider (kurallara aykırı değildir).


Yaparak bir bayt kurtarabilirsinfrom itertools import*
DJMcMayhem

4

JavaScript ( ES6 ) 117

Her olası bölmeyi denemek için bir bit maskesi kullanmak, bu nedenle 31 maddeyle sınırlıdır (kurallara uygun). Ref cevabı gibi sadece bir el çıkarır. Not: Math.ab'lerden kaçınmak için minimum farkı> = 0 arıyorum, her min <0 için olduğu gibi, başka> 0 var, sadece ellerinizi takas ediyorum.

Test etmek için: snippet'i Firefox'ta çalıştırın, birbirinden virgül veya ayrılmış bir sayı listesi girin.

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 bayt

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

Bir yandan bir öğe listesi çıkarır. Kayıp unsurlar diğer taraftan gider.

Kullanımı: f [7,7,7,10,11] ->[7,7,7]

sGiriş listesinin tüm alt dizileri için , ve larasındaki seksiklik elementleri arasındaki ağırlık farkının mutlak değerini hesaplayın l. Asgari bul.


1

Haskell, 51 bayt

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

Çıktı formatı, sol ağırlıklar pozitif ve sağ ağırlıklar negatiftir.

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

Her olası bölünmeyi oluşturmak için, mapM(\x->[x,-x])lher olası alt öğe kümesini yok etmek için kullanıyoruz . Sonra,((,)=<<abs.sum) her birini mutlak toplamıyla snd$minimum$((,)=<<abs.sum)etiketler ve en küçük etiketli öğeyi alır.

Tip kontrolü sorunları nedeniyle puansız alamadım.


@WillNess Geçerli sürümde hepsi hazır.
xnor

BTW aşağıdaki nokta içermeyen kod GHCi istemi çalışıyor: snd.minimum.map((,)=<<abs.sum).mapM(\x->[x,-x]). 47 bayttır. (yüklü eski bir sürümü olsa da ...)
Will Ness

0

R (234)

R ile daha uzun ve daha yavaş bir çözüm

İşlev:

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]]])}


Beklenen girdi - ağırlıklar ile vektör.
Beklenen çıktı - bir yandan ağırlıklar ile vektör.


Örnek

> 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

İnsan tarafından okunabilen kod sürümü:

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

Aksiyom, 292 bayt

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])

Bir kaba kuvvet uygulaması. Bu kümeyi minimize eder

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

çünkü minimum ise

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

o da minimum olurdu

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

nerede (azaltmak (+, a) - redüksiyon (+, r)) ve azaltmak (+, r) iki poşetin 2 ağırlığıdır. Ungolf ve sonuçları

-- 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.