Ajude-me a carregar minhas sacolas de compras


26

Era uma noite quente de verão ...

quando meu carro estúpido decidiu parar no meio da estrada no meu caminho de volta do supermercado. Empurrei-o para a linha lateral e decidi ir para casa. Abri o porta-malas para tirar as compras e as coisas restantes. Foi então que notei que os itens não estavam uniformemente ensacados. Algumas sacolas tinham itens mais pesados, enquanto outras tinham poucas coisas mais leves - algumas até tinham uma mistura desses itens. Para facilitar o transporte, decidi agrupar tudo em duas malas e fazer com que seus pesos fossem o mais próximo possível um do outro.

Fazendo o meu caminho para o centro

Seu objetivo

é me ajudar a reorganizar os itens em duas sacolas de compras, de modo que a diferença entre as duas seja o mais próxima possível de zero.
Matematicamente:

PESO MÃO ESQUERDA - PESO MÃO DIREITA ≈ 0

Exemplo

Se eu tivesse apenas 2 itens, Pão e manteiga de amendoim, e o peso do pão for 250 gramas e a manteiga de amendoim for 150 gramas, a melhor maneira é carregá-los separadamente com as duas mãos.

W LH - W RH = W (PÃO) - W (P. MANTEIGA)
250 - 150 = 100

A outra possibilidade é:

W (PÃO, P. MANTEIGA) - W (mão vazia) = (250 + 150) - 0 = 400

Isso não é melhor do que o nosso primeiro caso, então você deve ir com o primeiro.

Seu código deve

  1. anote números indicando pesos de itens na sacola de compras. As unidades não são importantes, mas devem ser as mesmas (idealmente quilogramas ou gramas). A entrada pode ser feita uma por uma ou todas de uma vez. Você pode restringir a contagem total a 20 itens, no máximo, se desejar.
  2. Você escolhe o formato / tipo de entrada, mas nada deve estar presente além dos pesos.
  3. Qualquer idioma é permitido, mas atenha-se às bibliotecas padrão.
  4. Exibir saída. Novamente, você pode escolher o formato, mas explique o formato na sua postagem. ou seja, como podemos saber quais são os itens à esquerda e quais são os itens à direita.

Pontos

  1. O menor código vence.

Sugestão

Os dois possíveis algoritmos em que pude pensar são diferenciação (mais rápida) e permutações / combinações (mais lenta). Você pode usar esse ou qualquer outro algoritmo que faça o trabalho.


5
Eu como regra 2, é flexível, mas não permite fazer batota
edc65

2
Você basicamente reinventou o problema da mochila. en.wikipedia.org/wiki/Knapsack_problem
Sparr

Obrigado @Sparr Estou smaat ímpios (não realmente)
Renae Lider

2
Esse problema é muito prático e realista para este site.
Restabelece Monica iamnotmaynard

Respostas:


15

Pitão, 9 bytes

ehc2osNyQ

Formatos de entrada, saída:

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

Demonstração.

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.

Isso funciona porque yretorna os subconjuntos em uma ordem em que cada subconjunto e seu complemento são eqüidistantes do centro. Como a soma de um subconjunto e a soma de seu complemento sempre serão equidistantes do centro, a lista a seguir osNyQtambém terá essa propriedade. Assim, os dois elementos centrais de osNyQsão complementos e devem ter uma divisão ideal. Extraímos o primeiro desses dois elementos e o imprimimos.


A resposta do OP imprime apenas as malas em uma mão, então parabéns pela sua solução de 9 bytes.
Dennis

Sua gravação está com erros na entrada [7 7 7 10 11] Traceback (última chamada mais recente): Arquivo "pyth.py", linha 772, no <module> Arquivo "<string>", linha 4, no <module> Arquivo "/app/macros.py", linha 865, na ordem TypeError: tipos não-ordenáveis: int () <list ()
RosLuP 17/17/17

@RosLuP Isso funcionou na época, eu mudei algo sobre o sque fez parar de funcionar. As pessoas não gostaram da mudança, e seu comentário foi o empurrão final que eu precisava para mudar de volta.
Isaacg 18/11

No código comentado que não deve ser "subconjunto de Q", mas "sublista de Q"
RosLuP

@RosLuP Eu discordo - uma sub-lista é tipicamente contígua. Subconjunto e subsequência são dois termos para esse tipo de coisa.
Isaacg

6

Pyth, 16

ho.a-FsMNs./M.pQ

Isso leva as entradas como uma lista pitônica no STDIN. A saída é uma lista de 2 listas, com a primeira lista sendo os itens em uma bolsa e a segunda lista representando os itens na segunda bolsa. Esse bruto força todas as combinações, por isso será executado muito lentamente (ou ficará sem memória) para entradas grandes.

Experimente online aqui

Para suportar o tratamento de apenas uma entrada, isso aumenta para 17:

hho.a-FsMNs./M.pQ

Isso imprimirá os valores que aparecem em uma mão.


Esta é uma solução muito impressionante - não é óbvio que não dê respostas erradas como [[2], [1], [1]], mas acho que funciona, devido exatamente a como ./funciona.
Isaacg

Na verdade, acho que isso falha nos casos em que tudo acontece em uma mão, como quando há apenas um objeto.
Isaacg

@isaacg Eu meio que assumi que 1 objeto não era válido, pois você claramente precisava segurá-lo com uma mão. Eu realmente não saberia o que retornar por isso [[x], []]?
FryAmTheEggman

Acho que sim - provavelmente tudo bem, a menos que o OP diga o contrário.
Isaacg

@isaacg Publiquei uma resposta abaixo. Ele dá a resposta correta para um elemento (eu tinha para adicionar mais um byte para o código)
Renae Lider

6

CJam, 19 18 bytes

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

Essa é uma função anônima que exibe uma matriz de números inteiros da pilha e retorna uma matriz de números inteiros separados por um espaço.

Obrigado a @ jimmy23013 por seu :*truque engenhoso , que salvou 1 byte.

Experimente on-line no intérprete CJam .

Como funciona

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.

Denotar o peso total dos sacos de compra com W . Então, se as malas de uma das mãos pesarem L / 2 - D / 2 , as da outra mão deverão pesar e L - (L / 2 - D / 2) = L / 2 + D / 2 .

Estamos tentando minimizar a diferença D . Mas (W / 2 - D / 2) (W / 2 + D / 2) = W ^ 2/4 - D ^ 2/4 , que se torna maior à medida que D se torna menor.

Assim, o produto máximo corresponde à diferença mínima.


Eu acho que :*... W=deveria funcionar.
jimmy23013

@ jimmy23013: Obrigado! Isso tornou minha resposta muito mais interessante.
Dennis

5

Python 2.7, 161 , 160

código

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 uma mão = Peso total
W uma mão ~ Peso total / 2

Verifique se cada combinação está se aproximando da metade do peso total. Repita e encontre o melhor.

entrada

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

saída

(2, 3)

A tupla exibida vai em uma mão, as que não são exibidas vão na outra (não é contra as regras).


Você pode economizar um byte fazendo #from itertools import*
DJMcMayhem

4

JavaScript ( ES6 ) 117

Usando uma máscara de bits para tentar todas as divisões possíveis, é limitado a 31 itens (ok com as regras). Como a resposta ref, ela gera apenas uma mão. Nota: eu procuro a diferença mínima> = 0 para evitar Math.abs, pois para cada min <0 existe outro> 0, apenas trocando de mãos.

Para testar: execute o snippet no Firefox, insira uma lista de números separados por vírgula ou espaço.

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 bytes

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

Produz uma lista de itens em uma mão. Os elementos ausentes vão para o outro lado.

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

Para todas as subsequências sda lista de entrada, lcalcule o valor absoluto da diferença de peso entre se os elementos ausentes de l. Encontre o mínimo.


1

Haskell, 51 bytes

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

O formato de saída é que os pesos da esquerda são positivos e os da direita são negativos.

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

Para gerar todas as divisões possíveis, usamos mapM(\x->[x,-x])lpara negar todos os subconjuntos possíveis de elementos. Em seguida, ((,)=<<abs.sum)rotule cada um com sua soma absoluta e snd$minimum$((,)=<<abs.sum)use o menor elemento rotulado.

Não consegui obtê-lo sem pontos por causa de problemas de verificação de tipo.


@ WillNess Eles estão todos em prelúdio na versão atual.
xnor

BTW o código livre pontos a seguir funciona no GHCi prompt: snd.minimum.map((,)=<<abs.sum).mapM(\x->[x,-x]). São 47 bytes. (embora eu tenha uma versão mais antiga instalada ...)
Will Ness

0

R (234)

uma solução mais longa e mais lenta com R.

Função:

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


Entrada esperada - vetor com os pesos.
Saída prevista - vetor com os pesos de uma mão.


Exemplo

> 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

Versão do código legível por humanos:

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

Axioma, 292 bytes

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

Uma aplicação de força bruta. Isso minimizaria o conjunto

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

porque se é mínimo

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

também seria mínimo

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

onde (reduzir (+, a) -reduzir (+, r)) e reduzir (+, r) são o peso 2 de dois sacos. (Mas essa última fórmula não me parece mínima, na aplicação). Ungolf e resultados

-- 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.