ช่วยฉันพกถุงช้อปปิ้งของฉัน


26

มันเป็นช่วงเย็นของฤดูร้อนที่อบอุ่น ...

เมื่อรถที่โง่ของฉันตัดสินใจที่จะพังกลางถนนระหว่างทางกลับจากซุปเปอร์มาร์เก็ต ฉันผลักมันไปงานอดิเรกและตัดสินใจที่จะเดินกลับบ้าน ฉันเปิดท้ายรถเพื่อนำของออกจากร้านขายของชำและสิ่งของอื่น ๆ ที่เหลืออยู่ ตอนนั้นเองที่ฉันสังเกตเห็นว่าสิ่งของไม่ได้ถูกบรรจุอย่างเท่าเทียมกัน กระเป๋าบางใบมีของหนักมากขึ้นในขณะที่กระเป๋าอื่น ๆ มีของที่บางกว่า เพื่อให้ง่ายต่อการพกพาฉันตัดสินใจจัดกลุ่มทุกอย่างลงในกระเป๋าสองใบและทำให้น้ำหนักของพวกเขาใกล้เคียงกันมากที่สุด

ทำให้ทางของฉันในเมือง

เป้าหมายของคุณ

คือช่วยฉันจัดเรียงสิ่งของในถุงช้อปปิ้งสองถุงด้วยวิธีที่ความแตกต่างระหว่างถุงทั้งสองใกล้เคียงกับศูนย์มากที่สุด
ศาสตร์:

WEIGHT LEFT HAND - WEIGHT RIGHT HAND ≈ 0

ตัวอย่าง

หากฉันมีเพียง 2 รายการขนมปังและเนยถั่วและน้ำหนักของขนมปังคือ 250 กรัมและเนยถั่วเป็น 150 กรัมวิธีที่ดีที่สุดคือการพกพาพวกเขาแยกกันด้วยสองมือ

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

ความเป็นไปได้อื่น ๆ คือ:

W (BREAD, P.BUTTER) - W (มือเปล่า) = (250 + 150) - 0 = 400

นี่ไม่ได้ดีไปกว่าเคสแรกของเราดังนั้นคุณควรไปกับเคสแรก

รหัสของคุณควร

  1. ใส่ตัวเลขที่ระบุน้ำหนักของสินค้าในกระเป๋าช้อปปิ้ง หน่วยไม่สำคัญ แต่ควรจะเหมือนกัน (นึกคิดกิโลกรัมหรือกรัม) อินพุตสามารถทำได้ทีละตัวหรือทั้งหมดในคราวเดียว คุณสามารถ จำกัด จำนวนรวมได้สูงสุด 20 รายการหากต้องการ
  2. รูปแบบการป้อนข้อมูล / ประเภทขึ้นอยู่กับคุณที่จะเลือก แต่ไม่มีอะไรอื่นนอกเหนือจากน้ำหนัก
  3. อนุญาตให้ใช้ภาษาใดก็ได้ แต่ใช้กับไลบรารีมาตรฐาน
  4. แสดงผลออกมา คุณสามารถเลือกรูปแบบได้อีกครั้ง แต่อธิบายรูปแบบในโพสต์ของคุณ คือเราจะบอกได้อย่างไรว่าชิ้นไหนเป็นของมือซ้ายและของชิ้นไหนเป็นของมือขวา

จุด

  1. รหัสที่สั้นที่สุดชนะ

เปรย

อัลกอริทึมที่เป็นไปได้สองอย่างที่ฉันคิดได้คือความแตกต่าง (เร็วกว่า) และการเรียงสับเปลี่ยน / การรวม (ช้ากว่า) คุณสามารถใช้อัลกอริธึมเหล่านี้หรืออัลกอริธึมอื่นที่ทำงานได้


5
ฉันชอบกฎที่ 2 มีความยืดหยุ่น แต่ไม่อนุญาตให้มีการโกง
edc65

2
โดยทั่วไปคุณได้คิดค้นปัญหาเป้หลัง en.wikipedia.org/wiki/Knapsack_problem
Sparr

ขอบคุณ @Sparr ฉันชั่วร้าย smaat (ไม่จริง)
Renae Lider

2
ปัญหานี้ไกลเกินจริงและเป็นจริงสำหรับเว็บไซต์นี้
Reinstate Monica 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จะมีคุณสมบัตินี้ด้วย ดังนั้นองค์ประกอบที่สองของศูนย์osNyQคือการเติมเต็มและจะต้องมีการแยกที่ดีที่สุด เราแยกองค์ประกอบแรกจากสององค์ประกอบนั้นออกมาและพิมพ์


คำตอบของ OP จะพิมพ์เฉพาะถุงด้วยมือเดียวดังนั้นขอแสดงความยินดีกับโซลูชัน 9 ไบต์ของคุณ
Dennis

การเขียนของคุณถูกบั๊กสำหรับการป้อนข้อมูล [7 7 7 10 11] การย้อนกลับ (การโทรล่าสุดครั้งล่าสุด): ไฟล์ "pyth.py", บรรทัด 772, ใน <module> ไฟล์ "<string>", บรรทัด 4, ใน <module> ไฟล์ "/app/macros.py", บรรทัดที่ 865, ตามลำดับ TypeError: ประเภทที่ไม่สามารถจัดลำดับได้: int () <list ()
RosLuP

@RosLuP สิ่งนี้ใช้ได้ในเวลานั้นฉันเปลี่ยนบางอย่างเกี่ยวกับสิ่งsนั้นทำให้หยุดทำงาน ผู้คนไม่ชอบการเปลี่ยนแปลงและความคิดเห็นของคุณคือการผลักดันครั้งสุดท้ายที่ฉันต้องเปลี่ยนกลับ
isaacg

ในรหัสที่แสดงความคิดเห็นไม่ควรเป็น "ส่วนย่อยของ Q" แต่ "รายการย่อยของ Q"
RosLuP

@RosLuP ฉันไม่เห็นด้วย - รายการย่อยมักจะต่อเนื่องกัน การจัดกลุ่มและการเรียงลำดับเป็นสองคำสำหรับสิ่งนี้
isaacg

6

Pyth, 16

ho.a-FsMNs./M.pQ

นี่ใช้อินพุตเป็นรายการ pythonic บน STDIN เอาท์พุทเป็นรายการของ 2 รายการโดยมีรายการแรกเป็นรายการในหนึ่งถุงและรายการที่สองเป็นตัวแทนรายการในถุงที่สอง เดรัจฉานนี้บังคับให้ชุดค่าผสมทั้งหมดดังนั้นมันจะทำงานช้ามาก (หรือหน่วยความจำไม่เพียงพอ) สำหรับอินพุตขนาดใหญ่

ลองออนไลน์ได้ที่นี่

เพื่อรองรับการจัดการอินพุตเพียงหนึ่งค่าสิ่งนี้จะสูงถึง 17:

hho.a-FsMNs./M.pQ

สิ่งนี้จะพิมพ์ค่าที่ไปในมือเดียว


นี่เป็นวิธีแก้ปัญหาที่น่าประทับใจมาก - ไม่ชัดเจนเลยว่าไม่ได้ให้คำตอบที่ผิดพลาด[[2], [1], [1]]แต่ฉันคิดว่ามันใช้./งานได้ดี
isaacg

ที่จริงแล้วฉันคิดว่าสิ่งนี้จะล้มเหลวในทุกกรณีที่ทุกอย่างเป็นไปด้วยมือเดียวเช่นเมื่อมีวัตถุ 1 ชิ้นเท่านั้น
isaacg

@isaacg ฉันมีวัตถุปลอม 1 ชนิดที่ไม่ถูกต้องเนื่องจากคุณต้องถือมันไว้ในมือเดียว ฉันไม่รู้จะกลับไปหา[[x], []]อะไรดี
FryAmTheEggman

ฉันเดาอย่างนั้น - มันคงโอเคถ้า OP บอกอย่างอื่น
isaacg

@isaacg ฉันโพสต์คำตอบด้านล่าง มันจะให้คำตอบที่ถูกต้องสำหรับ 1 องค์ประกอบ (ฉันมีการเพิ่มหนึ่งไบต์มากขึ้นเพื่อรหัส)
Renae Lider

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 2

เราพยายามที่จะลดความแตกต่างของD แต่(W / 2 - D / 2) (W / 2 + D / 2) = W ^ 2/4 - D ^ 2/4ซึ่งจะใหญ่ขึ้นเมื่อDกลายเป็นเล็กลง

ดังนั้นผลิตภัณฑ์สูงสุดจะสอดคล้องกับความแตกต่างน้อยที่สุด


ฉันคิดว่า:*... W=ควรจะทำงาน
jimmy23013

@ jimmy23013: ขอบคุณ! นั่นทำให้คำตอบของฉันน่าสนใจยิ่งขึ้น
Dennis

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 one hand = น้ำหนักรวม
W one hand ~ น้ำหนักรวม / 2

ตรวจสอบว่าชุดค่าผสมแต่ละชุดมีน้ำหนักใกล้เคียงครึ่งหนึ่งของน้ำหนักทั้งหมดหรือไม่ วนซ้ำและค้นหาสิ่งที่ดีที่สุด

อินพุต

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

เอาท์พุต

(2, 3)

tuple ที่แสดงไปในมือข้างหนึ่ง, คนที่ไม่ได้แสดงไปในมืออื่น ๆ (มันไม่ได้เป็นไปตามกฎ)


คุณสามารถบันทึกหนึ่งไบต์โดยทำfrom itertools import*
DJMcMayhem

4

JavaScript ( ES6 ) 117

ใช้หน้ากากเล็ก ๆ น้อย ๆ เพื่อลองแยกทุกครั้งที่เป็นไปได้ดังนั้นจึงถูก จำกัด ไว้ที่ 31 รายการ (ตกลงกับกฎ) เช่นเดียวกับคำตอบอ้างอิงมันจะส่งออกมือเดียว หมายเหตุ: ฉันค้นหาความแตกต่างขั้นต่ำ> = 0 เพื่อหลีกเลี่ยง Math.abs สำหรับแต่ละนาที <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]

สำหรับ subsequences ทั้งหมด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

BTW รหัสจุดฟรีต่อไปทำงานที่ 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)) 

โดยที่ (ลด (+, a) - ลด (+, r)) และลด (+, r) คือน้ำหนัก 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.