Aiutami a portare le borse della spesa


26

Era una calda serata estiva ...

quando la mia stupida macchina decise di guastarsi in mezzo alla strada mentre tornavo dal supermercato. L'ho spinto a bordo campo e ho deciso di tornare a casa. Ho aperto il bagagliaio per portare fuori la spesa e le cose rimanenti. Fu allora che notai che gli articoli non erano stati insaccati in modo uniforme. Alcune borse avevano oggetti più pesanti mentre altre avevano poche cose più leggere - alcune addirittura avevano un mix di tali oggetti. Per facilitarne il trasporto, ho deciso di raggruppare tutto in due borse e di mettere i pesi il più vicino possibile.

sto andando giù in città

Il tuo obiettivo

è aiutarmi a riorganizzare gli articoli in due borse della spesa in modo tale che la differenza tra le due borse sia il più vicino possibile allo zero.
Matematicamente:

PESO MANO SINISTRA - PESO MANO DESTRA ≈ 0

Esempio

Se avessi solo 2 articoli, Pane e burro di arachidi, e il peso del pane fosse di 250 grammi e il burro di arachidi è di 150 grammi, il modo migliore è portarli separatamente in due mani.

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

L'altra possibilità è:

W (BREAD, P.BUTTER) - W (mano vuota) = (250 + 150) - 0 = 400

Questo non è meglio del nostro primo caso, quindi dovresti andare con il primo.

Il tuo codice dovrebbe

  1. accetta input di numeri che indicano i pesi degli articoli nel carrello. Le unità non sono importanti, ma dovrebbero essere le stesse (idealmente chilogrammi o grammi). L'input può essere fatto uno per uno o tutti contemporaneamente. Se lo desideri, puoi limitare il conteggio totale a un massimo di 20 articoli.
  2. Il formato / tipo di input dipende da te, ma nient'altro dovrebbe essere presente oltre ai pesi.
  3. È consentita qualsiasi lingua, ma attenersi alle librerie standard.
  4. Visualizza output. Ancora una volta, sei libero di scegliere il formato, ma spiega il formato nel tuo post. cioè, come possiamo sapere quali sono gli oggetti per la mano sinistra e quali sono gli oggetti per la mano destra.

Punti

  1. Il codice più corto vince.

Suggerimento

I due possibili algoritmi a cui potrei pensare sono la differenziazione (più veloce) e le permutazioni / combinazioni (più lente). È possibile utilizzare questi o altri algoritmi che svolgono il lavoro.


5
Mi piace la regola 2, è flessibile ma non consente di barare
edc65

2
Fondamentalmente hai reinventato il problema dello zaino. en.wikipedia.org/wiki/Knapsack_problem
Sparr

Grazie @Sparr I am wicked smaat (non proprio)
Renae Lider

2
Questo problema è troppo pratico e realistico per questo sito.
Ripristina Monica iamnotmaynard il

Risposte:


15

Pyth, 9 byte

ehc2osNyQ

Formati di input, output:

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

Dimostrazione.

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.

Questo funziona perché yrestituisce i sottoinsiemi in un ordine tale che ciascun sottoinsieme e il suo complemento sono equidistanti dal centro. Poiché la somma di un sottoinsieme e la somma del suo complemento saranno sempre equidistanti dal centro, anche l'elenco successivo osNyQavrà questa proprietà. Pertanto, i due elementi centrali di osNyQsono complementi e devono avere una divisione ottimale. Estraggiamo il primo di questi due elementi e lo stampiamo.


La risposta dell'OP stampa i sacchetti solo in una mano, quindi congratulazioni per la soluzione a 9 byte.
Dennis,

La tua scrittura è disturbata per l'input [7 7 7 10 11] Traceback (ultima chiamata più recente): file "pyth.py", linea 772, in <module> File "<string>", linea 4, in <module> File "/app/macros.py", riga 865, nell'ordine TypeError: tipi non ordinabili: int () <list ()
RosLuP

@RosLuP Funzionava in quel momento, ho cambiato qualcosa sche lo ha fatto smettere di funzionare. Alla gente non è piaciuta la modifica e il tuo commento è stato la spinta finale di cui avevo bisogno per cambiarla.
isaacg,

Nel codice commentato non dovrebbe essere "sottoinsieme di Q" ma "sottoelenco di Q"
RosLuP

@RosLuP Non sono d'accordo: un elenco secondario è in genere contiguo. Sottoinsieme e sottosequenza sono due termini per questo tipo di cose.
isaacg,

6

Pyth, 16

ho.a-FsMNs./M.pQ

Questo prende gli input come un elenco pitonico su STDIN. L'output è un elenco di 2 elenchi con il primo elenco costituito dagli elementi in un sacchetto e il secondo elenco che rappresenta gli articoli nel secondo sacchetto. Questo bruto forza tutte le combinazioni, quindi funzionerà molto lentamente (o esaurirà la memoria) per input di grandi dimensioni.

Provalo online qui

Per supportare la gestione di un solo input, questo arriva fino a 17:

hho.a-FsMNs./M.pQ

Questo stamperà i valori che vanno in una mano.


Questa è una soluzione davvero impressionante - non è affatto ovvio che non darà risposte difettose come [[2], [1], [1]], ma penso che funzioni, a causa di esattamente come ./funziona.
Isaacg,

In realtà, penso che ciò fallisca nei casi in cui tutto va in una mano, come quando c'è solo 1 oggetto.
Isaacg,

@isaacg Avevo supposto che 1 oggetto non fosse valido, dato che dovevi semplicemente tenerlo in una mano. Non saprei davvero cosa restituire per quello [[x], []],?
FryAmTheEggman,

Immagino di sì - probabilmente va bene se OP non dice diversamente.
Isaacg,

@isaacg Ho pubblicato una risposta qui sotto. Fornisce la risposta corretta per 1 elemento (ho dovuto aggiungere un altro byte al codice)
Renae Lider,

6

CJam, 19 18 byte

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

Questa è una funzione anonima che estrae un array di numeri interi dallo stack e restituisce un array di numeri interi separati da uno spazio.

Grazie a @ jimmy23013 per il suo :*trucco ingegnoso , che ha salvato 1 byte.

Provalo online nell'interprete CJam .

Come funziona

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.

Indichiamo il peso totale delle borse della spesa con W . Quindi, se i sacchetti in una delle mani pesano W / 2 - D / 2 , quelli nell'altra mano devono pesare e W - (W / 2 - D / 2) = W / 2 + D / 2 .

Stiamo cercando di ridurre al minimo la differenza D . Ma (W / 2 - D / 2) (W / 2 + D / 2) = W ^ 2/4 - D ^ 2/4 , che diventa più grande quando D diventa più piccola.

Pertanto, il prodotto massimo corrisponde alla differenza minima.


Penso che :*... W=dovrebbe funzionare.
jimmy23013,

@ jimmy23013: Grazie! Ciò ha reso la mia risposta molto più interessante.
Dennis,

5

Python 2.7, 161 , 160

codice

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

Algoritmo

2 x W una mano = Peso totale
W una mano ~ Peso totale / 2

Controlla se ogni combinazione si avvicina alla metà del peso totale. Scorri e trova il migliore.

ingresso

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

produzione

(2, 3)

La tupla visualizzata va in una mano, quelli che non vengono visualizzati vanno nell'altra (non è contro le regole).


È possibile salvare un byte eseguendofrom itertools import*
DJMcMayhem

4

JavaScript ( ES6 ) 117

Utilizzare una maschera di bit per provare ogni possibile divisione, quindi è limitato a 31 elementi (ok con le regole). Come la risposta ref, emette solo una mano. Nota: cerco la differenza minima> = 0 per evitare Math.abs, poiché per ogni min <0 ce n'è un altro> 0, scambiando solo le mani.

Per testare: esegui lo snippet in Firefox, inserisci un elenco di numeri separati da virgola o spazio.

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 byte

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

Emette un elenco di elementi in una mano. Gli elementi mancanti vanno invece.

Utilizzo: f [7,7,7,10,11]->[7,7,7]

Per tutte sle sottosequenze dell'elenco di input, lcalcolare il valore assoluto della differenza di peso tra se gli elementi mancanti di l. Trova il minimo.


1

Haskell, 51 byte

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

Il formato di output è che i pesi a sinistra sono positivi e quelli a destra sono negativi.

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

Per generare ogni possibile divisione, usiamo mapM(\x->[x,-x])lper annullare ogni possibile sottoinsieme di elementi. Quindi, ((,)=<<abs.sum)etichetta ognuno con la sua somma assoluta e snd$minimum$((,)=<<abs.sum)prendi l'elemento con l'etichetta più piccola.

Non ho potuto ottenerlo senza punti a causa di problemi di controllo del tipo.


@WillNess Sono tutti in preludio nella versione attuale.
xnor

BTW il codice libero-punto seguente funziona al prompt GHCi: snd.minimum.map((,)=<<abs.sum).mapM(\x->[x,-x]). Sono 47 byte. (anche se ho una versione precedente installata ...)
Will Ness,

0

R (234)

una soluzione più lunga e più lenta con R.

Funzione:

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


Input previsto - vettore con i pesi.
Uscita prevista - vettore con i pesi per una mano.


Esempio

> 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

Versione del codice leggibile dall'uomo:

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

Assioma, 292 byte

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

Un'applicazione di forza bruta. Ciò minimizzerebbe il set

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

perché se è minimo

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

sarebbe anche minimo

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

dove (riduci (+, a) -riduce (+, r)) e riduci (+, r) sono i 2 pesi di due sacchi (ma quest'ultima formula non mi trova il minimo, nell'applicazione). Ungolf e risultati

-- 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.