買い物袋を運ぶのを手伝ってください


26

暖かい夏の夜だった...

私の愚かな車がスーパーマーケットから帰る道の途中で故障することを決めたとき。私はそれを傍観者に押し、家に帰ることにした。トランクを開けて、食料品や残りのものを取り出しました。そのとき、アイテムが均等に袋詰めされていないことに気づきました。いくつかのバッグにはもっと重いものがあり、他のバッグには軽いものがほとんどありませんでした。私が持ち運びしやすいように、すべてを2つのバッグにまとめて、それらの重量をできる限り近づけることにしました。

ダウンタウンに向かって歩きます

あなたの目標

両方のバッグの差ができるだけゼロに近くなるように、2つのショッピングバッグのアイテムを並べ替えるのを手伝います。
数学的に:

WEIGHT LEFT HAND - WEIGHT RIGHT HAND ≈0

パンとピーナッツバターの2つのアイテムしかなく、パンの重量が250グラムで、ピーナッツバターが150グラムの場合、最良の方法は両手で別々に運ぶことです。

W LH - W RH = W (パン) - W (P.BUTTER)
250から150 = 100

他の可能性は次のとおりです。

W (パン、P.BUTTER) - W (空手) =(250 + 150) - 0 = 400

これは最初のケースよりも良くないため、最初のケースを使用する必要があります。

あなたのコードは

  1. ショッピングバッグ内のアイテムの重量を示す数値を入力します。単位は重要ではありませんが、同じである必要があります(理想的にはキログラムまたはグラム)。入力は1つずつ、または一度にすべて実行できます。必要に応じて、合計数を最大20アイテムに制限できます。
  2. 入力形式/タイプはユーザーが選択できますが、重み以外には何も表示されません。
  3. 任意の言語を使用できますが、標準ライブラリに固執します。
  4. 出力を表示します。繰り返しますが、形式は自由に選択できますが、投稿で形式を説明してください。つまり、どのアイテムが左手アイテムであり、どのアイテムが右手アイテムであるかをどのように判断できますか。

ポイント

  1. 最短のコードが優先されます。

ヒント

私が考えることができる2つの可能なアルゴリズムは、微分(高速)と順列/組み合わせ(低速)です。これらまたはジョブを実行する他のアルゴリズムを使用できます。


5
私はルール2が好きですが、柔軟性がありますが、不正行為は許可されません
-edc65

2
あなたは基本的にナップザックの問題を再発明しました。en.wikipedia.org/wiki/Knapsack_problem
Sparr

ありがとう@Sparr私は(本当にではない)邪悪なスマート
ライダー

2
この問題は、このサイトにとってはあまりにも実用的で現実的です。
モニカiamnotmaynard

回答:


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もこのプロパティがあります。したがって、の中央の2つの要素osNyQは補数であり、最適な分割が必要です。これら2つの要素の最初の要素を抽出して印刷します。


OPによる答えは、片手でバッグを印刷するだけなので、9バイトのソリューションにおめでとうございます。
デニス

あなたの書き込みは入力のためにバグを起こします"/app/macros.py"、行865、順序TypeError:順序付け不可能な型:int()<list()
RosLuP

@RosLuPこれは当時機能していましたが、機能をs停止するように変更しました。人々は変更を好まなかったので、あなたのコメントは私がそれを元に戻すために必要な最後のプッシュでした。
-isaacg

コメントされたコードでは、「Qのサブセット」ではなく「Qのサブリスト」である必要があります
-RosLuP

@RosLuP私は同意しません-サブリストは通常​​連続しています。サブセットとサブシーケンスは、この種の2つの用語です。
isaacg

6

Pyth、16

ho.a-FsMNs./M.pQ

これは、入力をSTDINのpythonicリストとして受け取ります。出力は2つのリストのリストで、最初のリストは1つのバッグのアイテムであり、2番目のリストは2番目のバッグのアイテムを表します。このブルートはすべての組み合わせを強制するため、大きな入力に対しては非常に低速で実行されます(またはメモリ不足になります)。

こちらからオンラインでお試しください

1つの入力のみの処理をサポートするために、これは17まで行われます。

hho.a-FsMNs./M.pQ

これにより、片手で値が出力されます。


これは非常に印象的なソリューションです-のような誤った答えを与えないことはまったく明らかではありません[[2], [1], [1]]が、正確に機能するため、それが機能すると思います./
isaacg

実際、オブジェクトが1つしかない場合のように、すべてが片手で進む場合、これは失敗すると思います。
isaacg

@isaacg片方の手でそれを保持しなければならないので、1つのオブジェクトが有効ではないと仮定しました 私はそのために何を返すべきか本当に知りませんか[[x], []]
FryAmTheEggman

そうだと思います-OPが特に断らない限り、おそらく大丈夫です。
isaacg

@isaacg以下の回答を投稿しました。それは1つの要素に対して正しい答えを与えます(コードにもう1バイト追加する必要がありました)
レナエライダー

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 x W 片手 =総重量
W 片手〜総重量/ 2

各組み合わせが総重量の半分に近づいているかどうかを確認します。繰り返し、最適なものを見つけます。

入力

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

出力

(2, 3)

表示されたタプルは一方に表示され、表示されていないタプルは他方に表示されます(ルールに違反していません)。


以下を行うことで1バイト節約できますfrom itertools import*
DJMcMayhem

4

JavaScript(ES6)117

ビットマスクを使用してすべての可能な分割を試行するため、31アイテムに制限されます(ルールで問題ありません)。ref answerのように、それは片手だけを出力します。注:Math.absを避けるために最小差> = 0を探します。各min <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重み差の絶対値を計算します。最小値を見つけます。sl


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バイトです。(古いバージョンがインストールされていますが...)
ネスは16:30

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

ifが最小であるため

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つの袋の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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.