Giúp tôi mang túi đi mua sắm


26

Đó là một buổi tối mùa hè ấm áp ...

khi chiếc xe ngu ngốc của tôi quyết định bị hỏng giữa đường trên đường trở về từ siêu thị. Tôi đẩy nó sang bên lề và quyết định đi bộ về nhà. Tôi mở cốp để lấy hàng tạp hóa và những thứ còn lại. Đó là lúc tôi nhận thấy các mặt hàng không được đóng gói đều. Một số túi có nhiều vật nặng hơn trong khi một số khác có vài thứ nhẹ hơn - một số thậm chí còn có sự pha trộn của các vật phẩm đó. Để giúp tôi dễ dàng mang theo, tôi quyết định nhóm tất cả mọi thứ vào hai túi và làm cho trọng lượng của chúng càng gần nhau càng tốt.

Đi vào trung tâm thành phố

Mục tiêu của bạn

là để giúp tôi sắp xếp lại các mặt hàng vào hai túi mua sắm theo cách sao cho sự khác biệt giữa cả hai túi gần bằng 0 nhất có thể.
Về mặt toán học:

TRỌNG LƯỢNG TAY TRÁI TAY - TAY TRỌNG LƯỢNG TAY 0

Thí dụ

Nếu tôi chỉ có 2 món, Bánh mì và Bơ đậu phộng, và trọng lượng của bánh mì là 250 gram và bơ đậu phộng là 150 gram, cách tốt nhất là mang chúng riêng biệt bằng hai tay.

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

Khả năng khác là:

W (BREAD, P.BUTTER) - W (tay không) = (250 + 150) - 0 = 400

Điều này không tốt hơn trường hợp đầu tiên của chúng tôi, vì vậy bạn nên đi với trường hợp đầu tiên.

Mã của bạn nên

  1. lấy đầu vào của các con số biểu thị trọng lượng của các mặt hàng trong túi mua sắm. Các đơn vị không quan trọng, nhưng chúng phải giống nhau (lý tưởng là kilôgam hoặc gam). Đầu vào có thể được thực hiện từng cái một hoặc tất cả cùng một lúc. Bạn có thể giới hạn tổng số tối đa là 20 mục, nếu bạn muốn.
  2. Định dạng / loại đầu vào tùy thuộc vào bạn để chọn, nhưng không có gì khác phải có mặt ngoài trọng lượng.
  3. Bất kỳ ngôn ngữ đều được cho phép, nhưng dính vào các thư viện tiêu chuẩn.
  4. Hiển thị đầu ra. Một lần nữa, bạn thoải mái chọn định dạng, nhưng giải thích định dạng trong bài đăng của bạn. tức là, làm thế nào chúng ta có thể biết cái nào là vật phẩm tay trái và cái nào là vật phẩm tay phải.

Điểm

  1. Mã ngắn nhất sẽ thắng.

Dấu

Hai thuật toán có thể mà tôi có thể nghĩ đến là sự khác biệt (nhanh hơn) và hoán vị / kết hợp (chậm hơn). Bạn có thể sử dụng những thuật toán này hoặc bất kỳ thuật toán nào khác thực hiện công việc.


5
Tôi thích quy tắc 2, nó linh hoạt nhưng không cho phép gian lận
edc65

2
Về cơ bản, bạn đã phát minh lại vấn đề về chiếc ba lô. vi.wikipedia.org/wiki/Knapsack_pro Hiệu
Sparr

Cảm ơn bạn @Sparr Tôi xấu xa smaat (không thực sự)
Renae Lider

2
Vấn đề này là quá thực tế và thực tế cho trang web này.
Phục hồi Monica iamnotmaynard

Câu trả lời:


15

Bình thường, 9 byte

ehc2osNyQ

Định dạng đầu vào, đầu ra:

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

Trình diễn.

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.

Điều này hoạt động bởi vì ytrả về các tập hợp con theo thứ tự sao cho mỗi tập hợp con và phần bù của nó là tương đương với trung tâm. Vì tổng của một tập hợp con và tổng của phần bù của nó sẽ luôn luôn tương đương từ trung tâm, nên danh sách sau osNyQcũng sẽ có thuộc tính này. Do đó, hai yếu tố trung tâm osNyQlà bổ sung và phải có sự phân chia tối ưu. Chúng tôi trích xuất đầu tiên của hai yếu tố đó và in nó.


Câu trả lời của OP chỉ in các túi bằng một tay, vì vậy xin chúc mừng giải pháp 9 byte của bạn.
Dennis

Viết của bạn bị lỗi cho đầu vào [7 7 7 10 11] TracBack (cuộc gọi gần đây nhất): Tệp "pyth.py", dòng 772, trong <module> Tệp "<chuỗi>", dòng 4, trong <mô-đun> Tệp "/app/macros.py", dòng 865, theo thứ tự TypeError: các loại không thể sắp xếp: int () <list ()
RosLuP 17/11/17

@RosLuP Điều này hoạt động vào thời điểm đó, tôi đã thay đổi điều gì sđó khiến nó ngừng hoạt động. Mọi người không thích sự thay đổi và nhận xét của bạn là cú hích cuối cùng tôi cần để thay đổi lại.
isaacg

Trong mã nhận xét, nó không phải là "tập hợp con của Q" mà là "danh sách con của Q"
RosLuP

@RosLuP Tôi không đồng ý - một danh sách con thường liền kề nhau. Tập hợp con và sau đó là hai thuật ngữ cho loại điều này.
isaacg

6

Bình thường, 16

ho.a-FsMNs./M.pQ

Điều này lấy các đầu vào như một danh sách pythonic trên STDIN. Đầu ra là một danh sách gồm 2 danh sách với danh sách đầu tiên là các mục trong một túi và danh sách thứ hai đại diện cho các mục trong túi thứ hai. Kẻ vũ phu này buộc tất cả các kết hợp, vì vậy nó sẽ chạy rất chậm (hoặc hết bộ nhớ) cho các đầu vào lớn.

Dùng thử trực tuyến tại đây

Để hỗ trợ xử lý chỉ một đầu vào, điều này lên tới 17:

hho.a-FsMNs./M.pQ

Điều này sẽ in các giá trị đi trong một tay.


Đây là một giải pháp rất ấn tượng - hoàn toàn không rõ ràng rằng nó sẽ không đưa ra câu trả lời sai như thế nào [[2], [1], [1]], nhưng tôi nghĩ rằng nó hoạt động, do chính xác cách thức ./hoạt động.
isaacg

Trên thực tế, tôi nghĩ điều này thất bại trong trường hợp mọi thứ diễn ra trong một tay, như khi chỉ có 1 đối tượng.
isaacg

@isaacg Tôi đã loại 1 đối tượng giả định không hợp lệ, vì rõ ràng bạn chỉ cần cầm nó bằng một tay. Tôi thực sự không biết phải trả lại cái gì cho điều đó [[x], []]?
FryAmTheEggman

Tôi đoán vậy - có lẽ vẫn ổn trừ khi OP nói khác.
isaacg

@isaacg Tôi đã đăng một câu trả lời dưới đây. Nó đưa ra câu trả lời chính xác cho 1 phần tử (tôi đã phải thêm một byte vào mã)
Renae Lider

6

CJam, 19 18 byte

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

Đây là một hàm ẩn danh bật ra một mảng các số nguyên từ ngăn xếp và trả về một mảng các số nguyên cách nhau bởi một khoảng trắng.

Cảm ơn @ jimmy23013 vì :*thủ thuật khéo léo của anh ấy , đã tiết kiệm được 1 byte.

Hãy thử trực tuyến trong trình thông dịch CJam .

Làm thế nào nó hoạt động

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.

Biểu thị tổng trọng lượng của túi mua sắm với W . Sau đó, nếu các túi ở một trong hai tay nặng W / 2 - D / 2 , thì các túi trong tay kia phải cân và W - (W / 2 - D / 2) = W / 2 + D / 2 .

Chúng tôi đang cố gắng để giảm thiểu sự chênh lệch D . Nhưng (W / 2 - D / 2) (W / 2 + D / 2) = W ^ 2/4 - D ^ 2/4 , trở nên lớn hơn khi D trở nên nhỏ hơn.

Do đó, sản phẩm tối đa tương ứng với sự khác biệt tối thiểu.


Tôi nghĩ :*... W=nên làm việc.
jimmy23013

@ jimmy23013: Cảm ơn! Điều đó làm cho câu trả lời của tôi thú vị hơn rất nhiều.
Dennis

5

Trăn 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

Thuật toán

2 x W một tay = Tổng trọng lượng
W một tay ~ Tổng trọng lượng / 2

Kiểm tra xem mỗi kết hợp đang tiến gần đến một nửa tổng trọng lượng. Lặp đi lặp lại và tìm một trong những tốt nhất.

đầu vào

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

đầu ra

(2, 3)

Các tuple được hiển thị đi trong một tay, những cái không được hiển thị đi trong tay kia (nó không trái với quy tắc).


Bạn có thể tiết kiệm một byte bằng cách thực hiệnfrom itertools import*
DJMcMayhem

4

JavaScript ( ES6 ) 117

Sử dụng một mặt nạ bit để thử mọi phân chia có thể, do đó, nó bị giới hạn ở 31 mục (ok với các quy tắc). Giống như câu trả lời ref nó chỉ xuất ra một tay. Lưu ý: tôi tìm chênh lệch tối thiểu> = 0 để tránh Math.abs, vì với mỗi phút <0 có khác> 0, chỉ cần trao đổi tay.

Để kiểm tra: chạy đoạn mã trong Firefox, nhập danh sách các số dấu phẩy hoặc dấu cách.

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]

Xuất ra một danh sách các mục trong một tay. Các yếu tố còn thiếu đi đến mặt khác.

Cách sử dụng: f [7,7,7,10,11]->[7,7,7]

Đối với tất cả các phần sau scủa danh sách đầu vào, hãy ltính giá trị tuyệt đối của chênh lệch trọng số giữa svà các phần tử còn thiếu của l. Tìm mức tối thiểu.


1

Haskell, 51 byte

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

Định dạng đầu ra là trọng lượng tay trái là dương và trọng lượng tay phải là âm.

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

Để tạo mọi phân chia có thể, chúng tôi sử dụng mapM(\x->[x,-x])lđể phủ định mọi tập hợp con có thể của các phần tử. Sau đó, ((,)=<<abs.sum)gắn nhãn cho mỗi cái với tổng tuyệt đối của nó và snd$minimum$((,)=<<abs.sum)lấy phần tử được gắn nhãn nhỏ nhất.

Tôi không thể có được nó miễn phí vì các vấn đề kiểm tra loại.


@WillNess Tất cả đều là khúc dạo đầu trong phiên bản hiện tại.
xnor

BTW mã không có điểm sau đây hoạt động tại dấu nhắc GHCi : snd.minimum.map((,)=<<abs.sum).mapM(\x->[x,-x]). Đó là 47 byte. (mặc dù tôi đã cài đặt phiên bản cũ hơn ...)
Will Ness

0

R (234)

một giải pháp dài hơn và chậm hơn với R.

Chức năng:

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


Đầu vào dự kiến ​​- vector với các trọng số.
Đầu ra dự kiến ​​- vector với trọng lượng cho một tay.


Thí dụ

> 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

Phiên bản mã có thể đọc được của con người:

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

Tiên đề, 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])

Một ứng dụng vũ phu. Điều này sẽ giảm thiểu tập hợp

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

bởi vì nếu là tối thiểu

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

nó cũng sẽ là tối thiểu

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

trong đó (giảm (+, a) -reduce (+, r)) và giảm (+, r) là 2 trọng số của hai túi. (Nhưng công thức cuối cùng đó không tìm thấy ở tôi mức tối thiểu, trong ứng dụng). Ungolf và kết quả

-- 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.