帮我carry购物袋


26

那是一个温暖的夏日傍晚。

当我愚蠢的汽车决定在从超市回来的路上在路中间抛锚时。我把它推到了场外,决定步行回家。我打开后备箱取出杂货和剩余的东西。那时我才发现这些物品装不平。有些袋子的物品较重,而有些袋子的重量较轻-有些甚至混合了此类物品。为了便于携带,我决定将所有物品归为两个袋子,并使其重量尽可能地接近。

通往市区

你的目标

是为了帮助我将商品重新放入两个购物袋中,使两个购物袋之间的差异尽可能接近零。
数学上:

左手重量— 右手重量≈0

如果我只有面包和花生酱这两种食品,而面包的重量是250克,花生酱的重量是150克,最好的方法是用两只手分别携带。

W LH -W RH = W (面包) -W (黄油)250-150
= 100

另一种可能性是:

W (面包,黄油) -W (空手) =(250 + 150)-0 = 400

这并不比我们的第一种情况更好,因此您应该选择第一种情况。

您的代码应

  1. 输入表示购物袋中物品重量的数字。单位并不重要,但是它们应该相同(理想情况下为千克或克)。输入可以一次完成,也可以一次完成。如果需要,您可以将总数限制为最多20个项目。
  2. 输入格式/类型由您决定,但是除权重外,其他任何内容都不能出现。
  3. 允许使用任何语言,但要遵循标准库。
  4. 显示输出。同样,您可以自由选择格式,但可以在帖子中说明格式。即,我们如何分辨哪些是左手物品,哪些是右手物品。

点数

  1. 最短的代码胜出。

暗示

我可能想到的两种可能的算法是微分(更快)和排列/组合(慢)。您可以使用这些算法或其他任何可以完成任务的算法。


5
我喜欢规则2,它很灵活,但不允许作弊
edc65

2
您基本上已经彻底改造了背包问题。en.wikipedia.org/wiki/Knapsack_problem
Sparr,2015年

谢谢@Sparr我是邪恶的Smaat(不是真的)
Renae Lider

2
这个问题对于这个站点来说太实际和太现实了。
恢复莫妮卡iamnotmaynard

Answers:


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是互补的,并且必须具有最佳分割。我们提取这两个元素中的第一个并打印。


OP的答案只用一只手就能打印出袋子,所以恭喜您使用了9字节的解决方案。
丹尼斯

输入[7 7 7 10 11]的写操作有误“ /app/macros.py”,行865,按TypeError顺序排列:乱序类型:int()<list()
RosLuP

@RosLuP当时有效,我s对此进行了一些更改,使其停止工作。人们不喜欢该更改,您的评论是我需要将其更改回的最后推动力。
isaacg

在注释的代码中,它不应为“ Q的子集”,而应为“ Q的子列表”
RosLuP

@RosLuP我不同意-子列表通常是连续的。子集和子序列是此类事物的两个术语。
isaacg

6

珀斯,16岁

ho.a-FsMNs./M.pQ

这会将输入作为STDIN上的pythonic列表。输出是2个列表的列表,第一个列表是一个袋子中的物品,第二个列表表示第二个袋子中的物品。这种蛮力迫使所有组合生效,因此对于大型输入而言,它将运行非常缓慢(或耗尽内存)。

在这里在线尝试

为了支持仅处理一个输入,最多需要17个:

hho.a-FsMNs./M.pQ

这将打印出一手可用的值。


这是一个非常令人印象深刻的解决方案-一点也不明显,它不会给出像这样的错误答案[[2], [1], [1]],但我认为它的确有效,因为它的工作原理确实如此./
isaacg

实际上,我认为这在万事俱备的情况下会失败,例如只有一个对象时。
isaacg

@isaacg我有点假设1个对象无效,因为您显然只需要一只手握住它。我真的不知道会得到什么回报[[x], []]
FryAmTheEggman 2015年

我想是的-除非OP另有说明,否则可能还可以。
isaacg

@isaacg我在下面发布了答案。它为1个元素给出了正确的答案(我必须在代码中再添加一个字节)
Renae Lider 2015年

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 2015年

@ jimmy23013:谢谢!这使我的回答更加有趣。
丹尼斯2015年

5

Python 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 x W 一只手 =总重量
W 一只手〜总重量/ 2

检查每种组合是否接近总重量的一半。迭代并找到最好的一个。

输入

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

输出

(2, 3)

显示的元组一方面进入,未显示的另一方面进入(这不违反规则)。


您可以这样做来节省一个字节from itertools import*
DJMcMayhem

4

JavaScript(ES6)117

使用位掩码尝试所有可能的拆分,因此它限制为31个项目(可以使用规则)。像参考答案一样,它只输出一只手。注意:为了避免Math.abs,我寻找最小差异> = 0,因为每分钟<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个字节。(尽管我确实安装了旧版本...)
Will Ness

0

R(234)

使用R的更长和更慢的解决方案。

功能:

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

其中(reduce(+,a)-reduce(+,r))和reduce(+,r)是两个袋子的2重量。(但最后一个公式对我而言没有找到最小值)。高低杠和结果

-- 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.