쇼핑백을 가지고 갈 수 있도록 도와주세요


26

따뜻한 여름 저녁이었습니다 ...

내 어리석은 차가 슈퍼마켓에서 돌아 오는 길의 한가운데서 고장 났을 때 나는 그것을 부업으로 밀고 집으로 걸어 가기로 결정했다. 나는 식료품과 남은 물건을 꺼내기 위해 트렁크를 열었습니다. 그때 물품이 고르게 포장되지 않았다는 것을 알게되었습니다. 일부 가방에는 더 무거운 물건이 있었지만 다른 가방에는 가벼운 물건이 거의 없었습니다. 휴대하기 쉽도록 모든 것을 두 개의 가방에 그룹화하고 무게를 가능한 한 가깝게 만들기로 결정했습니다.

시내로가는 길

네 목표

두 백의 차이가 최대한 0에 가까워 지도록 두 개의 쇼핑백에 상품을 다시 정렬하는 데 도움이됩니다.
수학적으로 :

체중 왼쪽 손 — 체중 오른쪽 손 ≈ 0

빵과 땅콩 버터 2 개만 가지고 빵의 무게가 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

감사합니다 @Sparr 나는 사악한 smaat입니다 (실제로는 아닙니다)
Renae Lider

2
이 문제는이 사이트에 비해 너무 실용적이고 현실적입니다.
복원 Monica 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 행, <모듈> 파일의 "<문자열>", 4 행. "/app/macros.py", 865 행, TypeError : unorderable types : int () <list ()
RosLuP

@RosLuP 이것은 당시에 효과가 있었기 s때문에 작동을 멈추게 한 것에 대해 무언가를 바꿨습니다 . 사람들은 그 변화를 좋아하지 않았으며, 귀하의 의견은 제가 그것을 바꾸어야 할 마지막 추진이었습니다.
isaacg 1

주석 처리 된 코드에서 "Q의 하위 집합"이 아니라 "Q의 하위 목록"이어야합니다
RosLuP

@RosLuP 동의하지 않습니다. 하위 목록은 일반적으로 인접합니다. 서브셋과 서브 시퀀스는 이런 종류의 용어입니다.
isaacg

6

피스, 16

ho.a-FsMNs./M.pQ

이것은 입력을 STDIN의 pythonic list로 가져옵니다. 출력은 두 개의 목록으로 구성되며 첫 번째 목록은 한 백에있는 항목이고 두 번째 목록은 두 번째 백에있는 항목을 나타냅니다. 이 무차별 동작은 모든 조합을 강제하므로 큰 입력의 경우 매우 느리게 (또는 메모리 부족) 실행됩니다.

여기에서 온라인으로 사용해보십시오

하나의 입력 만 처리 할 수 ​​있도록 최대 17 개가됩니다.

hho.a-FsMNs./M.pQ

한 손에 들어가는 값을 인쇄합니다.


이것은 매우 인상적인 솔루션입니다-와 같은 잘못된 답변을 제공 [[2], [1], [1]]하지는 않지만, 작동 방식이 정확하기 때문에 작동한다고 생각 ./합니다.
isaacg 2016 년

실제로, 나는 물체가 하나 뿐인 것처럼 모든 것이 한 손으로 진행되는 경우에는 이것이 실패한다고 생각합니다.
isaacg 2016 년

@isaacg 나는 한 손으로 잡고 있어야하기 때문에 1 개의 객체가 유효하지 않다고 가정했습니다. 나는 그것을 위해 무엇을 돌려 줄지 정말로 모른다 [[x], []].
FryAmTheEggman 1

나는 그렇게 생각합니다-OP가 달리 언급하지 않는 한 아마도 괜찮습니다.
isaacg 2016 년

@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 이어야합니다 .

차이 D 를 최소화하려고합니다 . 그러나 (W / 2-D / 2) (W / 2 + D / 2) = W ^ 2 / 4-D ^ 2 / 4D 가 작아 질 수록 커 집니다.

따라서 최대 곱은 최소 차이에 해당합니다.


나는 :*... W=작동해야 한다고 생각 합니다.
jimmy23013

@ jimmy23013 : 감사합니다! 그것은 내 대답을 훨씬 더 재미있게 만들었습니다.
Dennis

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)

표시된 튜플은 한 손에 들어가고 표시되지 않은 튜플은 다른 손에갑니다 (규칙에 위배되지 않음).


당신은 수행하여 하나의 바이트를 절약 할 수from itertools import*
DJMcMayhem

4

자바 스크립트 ( ES6 ) 117

비트 마스크를 사용하여 가능한 모든 분할을 시도하므로 31 개 항목으로 제한됩니다 (규칙에 따름). 심판 답변처럼 한 손만 출력합니다. 참고 : 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

하스켈, 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

하스켈, 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)) 

여기서 (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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.