래프팅 문제 (백팩 변형)


20

나로부터의 첫 번째 퍼즐, 기꺼이 개선을위한 제안!

시나리오는 다음과 같습니다. 급류 래프팅 회사의 관리자로 일합니다. 매일 아침, 예약 목록이 제공되며, 뗏목으로 분류해야합니다. 선택한 언어로 프로그램이나 기능을 작성하십시오.

각 뗏목은 최대 n고객을 보유하고 있으며 각 예약은 1 n명 에서 1 명까지 포함됩니다 (포함). 다음 규칙을 준수해야합니다.

  • 그룹을 나눌 수 없습니다. 함께 예약 한 경우 모두 동일한 뗏목에 있어야합니다.

  • 뗏목의 수를 최소화해야합니다.

  • 두 가지 선행 규칙에 따라 그룹은 뗏목 사이에 최대한 균등하게 분산되어야합니다.

입력. 숫자 n(이는 양의 정수라고 가정 할 수 있음) 및 모든 예약의 크기입니다. 당신의 언어가 그런 것들을 지원한다면 이것은 배열,리스트 또는 유사한 데이터 구조 일 수 있습니다. 이 모든 것은 1과 사이의 양의 정수 n입니다. 예약 순서는 정의되어 있지 않으며 중요하지도 않습니다.

산출. 뗏목 하중으로 그룹화 된 예약 번호 목록. 그룹화는 다음과 같이 분명하게 표시되어야합니다.

  • 리스트 또는 배열의 배열
  • 각 뗏목에 대한 쉼표로 구분 된 목록. 각 뗏목 사이의 줄 바꿈.

세 번째 규칙을 구현하는 방법은 사용자의 몫이지만 평균 뗏목 점유율을 찾고 가능한 한 편차를 최소화해야합니다. 다음은 몇 가지 테스트 사례입니다.

n  Bookings       Output
6  [2,5]          [5],[2]
4  [1,1,1,1,1]    [1,1,1],[1,1]
6  [2,3,2]        [2,2],[3]
6  [2,3,2,3]      [2,3],[2,3]
6  [2,3,2,3,2]    [2,2,2],[3,3]
12 [10,8,6,4,2]   [10],[8,2],[6,4]
6  [4,4,4]        [4],[4],[4]
12 [12,7,6,6]     [12],[7],[6,6]

가장 짧은 코드로 표준 규칙이 적용됩니다. 즐기세요!

편집; 세 번째 규칙에 대해 가능한 한 동일하게 정의하는 제안 된 방법 입니다.

뗏목의 수가 r결정 되면 (두 번째 규칙에 따름), 평균 점유량 a은 예약을 합산하고로 나누어 계산할 수 있습니다 r. 각 뗏목에 대해 평균 점유율과의 편차는을 사용하여 찾을 수 있습니다 d(x) = abs(n(x)-a). 여기서 n(x)각 뗏목의 인원수는 1 <= x <= r입니다. f(y)엄격하게 양수이고 모든 양수에 대해 엄격하게 양의 1 차 및 음수가 아닌 2 차 도함수를 갖는 연속적인 단일 값 함수의 경우 모든 yF의 합계로 음이 아닌 양을 정의 합니다 f(d(x)), 1 <= x <= r. 처음 두 규칙을 충족시키는 뗏목 할당을 선택 F하고 전체 최소값과 동일한 곳 은 세 번째 규칙도 충족합니다.


3
나중에 참조 할 수 있도록 샌드 박스 에 게시하여 게시하기 전에 챌린지에 대한 피드백을받을 수 있습니다.
밀 마법사

프로그래밍 퍼즐 및 코드 골프에 오신 것을 환영합니다! 이것은 첫 번째 도전임을 알고 좋은 도전처럼 보입니다. 그러나 다음에 샌드 박스에 도전 과제를 먼저 게시하는 것이 더 좋을 수 있으므로 사람들이 제안 사항을 제시 할 수 있습니다. 그런 다음 도전이 완료되었다고 생각되면 기본 사이트에 게시 할 수 있습니다. 읽어 주셔서 감사합니다. 즐거운 하루 보내세요!
Matthew Roh

가능한똑같이 어떻게 측정합니까?
데니스

@ 데니스; 이것을 편집에서 제안하는 방법을 제안합니다. 그러나 다른 방법을 사용하여 대답을 정당화 할 수 있다면 괜찮습니다.
Gwyn

1
유효한 것과 그렇지 않은 것을 분명하고 최신 편집으로 그 imo를 달성하는 한 구현에 맡기는 것은 괜찮습니다. 그래도 우리는 g(y) = y(두 번째 파생 0) 또는 g(y) = y²(첫 번째 0 사용)을 사용할 수 없다는 것에 놀랐습니다 y = 0.
데니스

답변:


2

Perl 6 , 163158 바이트

{[grep $^n>=*.all.sum,map ->\p{|map {p[0,|$_ Z..^|$_,p]},(1..^p).combinations},$^s.permutations].&{.grep: .map(+*).min}.min({.map((*.sum-$s.sum/$_)**2).sum})}

온라인으로 사용해보십시오!

작동 원리

  • map ->\p{|map {p[0,|$_ Z..^|$_,p]},(1..^p).combinations},$^s.permutations

    입력 배열의 모든 순열에 대해 가능한 모든 파티션을 생성합니다.

  • grep $^n>=*.all.sum,

    뗏목이 초과 예약되지 않은 것을 필터링합니다.

  • .&{.grep: .map(+*).min}

    뗏목 수가 최소 인 것을 필터링합니다.

  • .min({.map((*.sum-$s.sum/$_)**2).sum})}

    최소 ∑ (n x -a) 2로 첫 번째를 구합니다 .

@ Pietu1998 덕분에 -4 바이트


.abs결과를 제곱 하면해야 합니까?
PurkkaKoodari

@ Pietu1998 : 잘 모르겠습니다.
smls

3

하스켈 226 228 234 268 바이트

Haskell의 순진한 답변

import Data.List
o=map
u=sum
p=foldr(\x t->o([x]:)t++[(x:y):r|(y:r)<-t>>=permutations])[[]]
m x=foldl(\[m,n]x->[m+(x-m)/(n+1),n+1])[0,0]x!!0
a!z=abs$u z-a
s t=(length t,u$o((m$o u t)!)t)
a n=head.sortOn s.filter(all$(<=n).u).p

또는 언 골프

partition' :: [a] -> [[[a]]]
partition' [] = [[]]
partition' (x:xs) = [[x]:ps     | ps <- partition' xs]
                 ++ [(x:p):rest | ps <- partition' xs, (p:rest) <- permutations ps]

-- from Data.Statistics
mean :: [Double] -> Double
mean xs = fst $ foldl (\(m, n) x -> (m+(x-m)/n+1, n+1)) (0, 0) xs

diff :: Double -> [Double] -> Double
diff avg xs = abs $ sum xs - avg

rawScore :: [[Double]] -> Double
rawScore xs = sum . map (diff avg) $ xs where avg = mean . map sum $ xs

score :: [[Double]] -> (Int, Double)
score xs = (length xs, rawScore xs)

-- from Data.Ord
comparing :: (Ord b) => (a -> b) -> a -> a -> Ordering
comparing p x y = compare (p x) (p y)

candidates :: Double -> [Double] -> [[[Double]]]
candidates n xs = filter (all (\ ys -> sum ys <= n)) . partition' $ xs

answer :: Double -> [Double] -> [[Double]]
answer n xs = minimumBy (comparing score) $ candidates n xs

일부 테스트 사례

import Text.PrettyPrint.Boxes

testCases :: [(Double, [Double])]
testCases = [(6 , [2,5])
            ,(4 , [1,1,1,1,1])
            ,(6 , [2,3,2])
            ,(6 , [2,3,2,3])
            ,(6 , [2,3,2,3,2])
            ,(12, [10,8,6,4,2])
            ,(6 , [4,4,4])
            ,(12, [12,7,6,6])]

runTests tests = transpose 
                 $ ["n", "Bookings", "Output"]
                 : map (\(n, t) -> [ show . floor $ n
                                   , show . map floor $ t
                                   , show . map (map floor) $ a n t]) tests

test = printBox 
     . hsep 3 left . map (vcat top) . map (map text) . runTests $ testCases

어디 test수율

n    Bookings       Output
6    [2,5]          [[2],[5]]
4    [1,1,1,1]      [[1,1],[1,1,1]]
6    [2,3,2]        [[2,2],[3]]
6    [2,3,2,3]      [[2,3],[2,3]]
6    [2,3,2,3,2]    [[2,2,2],[3,3]]
12   [10,8,6,4,2]   [[10],[8,2],[6,4]]
6    [4,4,4]        [[4],[4],[4]]
12   [12,7,6,6]     [[12],[7],[6,6]]

편집하다

조언을 해주신 @flawr와 @nimi에게 감사드립니다.

p조금 숙청 했다.

몇 바이트를 깎았습니다.


1
대신에 설정 s=sum한 다음 사용할 수 있으며 대신 로 바꿀 수도 있습니다 . ssumfst$ ......!!0
flawr

1
당신은 대체 할 수 minimumBy(c s)head.sortOn s과 기능을 제거합니다 c. 또한 : \t->sum t<=n입니다 (<=n).sum.
nimi

@ flawr, 좋은 제안, 감사합니다!
walpen 2019

0

Python3, 224 바이트

def p(c):
 if len(c)==1:yield[c];return
 for s in p(c[1:]):
  for n,u in enumerate(s):yield s[:n]+[[c[0]]+u]+s[n+1:]
  yield[[c[0]]]+s
s=sum
r=lambda n,b:min(p(b),key=lambda c:s(abs(s(x)-s(b)/(s(b)//n+1))for x in c))

테스트 케이스 포함 :

tc = [[6,[2,5]],[4,[1,1,1,1,1]],[6,[2,3,2]],[6,[2,3,2,3]],[6,[2,3,2,3,2]],[12,[10,8,6,4,2]],[6,[4,4,4]],[12,[12,7,6,6]]]
for case in tc:
    print(str(case[0]).ljust(3),str(case[1]).ljust(16),"|",r(*case))

어떻게 작동합니까?

p함수는 단순히 주어진 목록의 모든 파티션 (하위 목록으로 나누는 가능한 모든 방법)을 생성합니다. s=sumsum 함수의 이름 만 바꾸면 마지막 행이 모든 작업을 수행합니다.

r=lambda n,b:min(p(b),key=lambda c:s(abs(s(x)-s(b)/(s(b)//n+1))for x in c))
r=lambda n,b:                                                               Initialize the lambda
                 p(b)                                                       Calculate all possible raft arrangements
                     ,key=lambda c:                                         Map the following lambda onto the list:
                                              s(b)/(s(b)//n+1)              Calculate the ideal average amount of people per raft
                                     abs(s(x)-                )             Calculate how close is the current raft
                                                               for x in c   For each raft in the partition
                                   s(                                    )  Sum it (the sum is a score of how close to ideal the function is),
             min(                                                         ) And find the lowest valued partition.

나는 이것이 골프, 특히 p기능으로 더 골프화 될 수 있다고 확신 하지만, 이미 몇 시간 동안이 작업을 했으므로 여기로 가십시오.

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