ラフティングの問題(ナップザックバリアント)


20

私からの最初のパズル、改善の提案を喜んで受け取った!

シナリオは次のとおりです。あなたは急流ラフティング会社のマネージャーとして働いています。毎朝、予約のリストが表示され、ラフトロードに並べ替える必要があります。選択した言語でこれを行うプログラムまたは関数を作成します。

各ラフトには最大数のnクライアントが収容され、各予約は1 n人以上のグループ(包括的)です。次のルールを順守する必要があります。

  • グループを分割することはできません。一緒に予約した場合、全員が同じラフトにいなければなりません。

  • いかだの数は最小限に抑える必要があります。

  • 上記の2つの規則に従って、グループはいかだの間で可能な限り均等に広げられなければなりません。

入力。 番号n(これは正の整数であると想定できます)、およびすべての予約のサイズ。言語がそのようなことをサポートしている場合、これは配列、リスト、または同様のデータ構造になります。これらはすべて1〜の正の整数になりnます。予約の順序は定義されておらず、重要でもありません。

出力。 いかだ積み荷にグループ化された予約番号のリスト。次のように、グループ化を明確に示す必要があります。

  • リスト、または配列の配列。
  • いかだごとのコンマ区切りリスト。各ラフト間の改行。

3番目のルールをどのように実装するかはユーザー次第ですが、これには、いかだの平均占有率を見つけ、それから可能な限り逸脱を最小限に抑えることが含まれます。ここにいくつかのテストケースがあります。

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]

標準ルールが適用され、最短のコードが優先されます。楽しむ!

編集済み; 3番目のルールを可能な限り均等に定義するための提案された方法。

いかだの数rが決定されると(2番目の規則に従い)、a予約を合計し、で割ることで平均占有率を計算できますr。各ラフトについて、を使用して平均占有率からの偏差を見つけることができますd(x) = abs(n(x)-a)。ここn(x)で、は各ラフトとの人数です1 <= x <= rf(y)厳密に正であり、すべての正に対して厳密に正の1次および非負の2次導関数をもつ連続的な単一値関数では、すべてのの合計としてy非負の量を定義します。最初の2つのルールを満たし、グローバルミニマムに等しいラフト割り当ての選択は、3番目のルールも満たします。Ff(d(x)), 1 <= x <= rF


3
後で参照できるように、投稿する前に、サンドボックスに投稿してチャレンジに関するフィードバックを得ることができます。
小麦ウィザード

プログラミングパズルとコードゴルフへようこそ!これは、あなたにとって最初の挑戦であることを知っている、素晴らしい挑戦のようです。ただし、次回は、最初にチャレンジをSandboxに投稿する方がよい場合があります。そうすれば、人々はそこで提案をすることができます。その後、チャレンジが完了したと思うとき、メインサイトに投稿できます。読んでくれてありがとう、そして良い一日を!
マシュー盧

可能な限り同等に測定される方法
デニス

@デニス; これを編集で定義する方法を提案します。ただし、別の方法があり、答えを正当化できる場合は問題ありません。
グウィン

1
何が有効で何が無効であるかが明確であり、最新の編集がそのimoを実現している限り、実装に任せることは問題ありません。ただし、g(y) = y(2番目の派生ゼロ)またはg(y) = y²(最初の派生ゼロ)を使用できないことに少し驚いてy = 0います。
デニス

回答:


2

Perl 6の163の 158バイト

{[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、その後、使用sの代わりにsum、そしておそらくあなたも置き換えることができfst$ ......!!0
flawr

1
functionで置き換えminimumBy(c s)head.sortOn s削除できますc。また、:\t->sum t<=nです(<=n).sum
nimi

@flawr、良い提案、ありがとう!
walpen

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=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))
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.