Problem raftingu (wariant plecakowy)

20

Pierwsze puzzle ode mnie, chętnie otrzymałem sugestie dotyczące ulepszeń!

Scenariusz jest następujący; Pracujesz jako kierownik firmy raftingowej. Każdego ranka dostajesz listę rezerwacji i musisz posortować je na ładunki tratwowe. Napisz program lub funkcję w wybranym języku, który to zrobi za Ciebie.

Każda tratwa może pomieścić maksymalnie nklientów, a każda rezerwacja dotyczy grupy od 1 do nosób (włącznie). Należy przestrzegać następujących zasad;

  • Żadne grupy nie mogą być podzielone. Jeśli zarezerwowali razem, wszyscy muszą być na tej samej tratwie.

  • Liczba tratw musi zostać zminimalizowana.

  • Z zastrzeżeniem dwóch powyższych zasad, grupy muszą być rozmieszczone tak równo, jak to możliwe między tratwami.

Wejścia Liczba n(możesz założyć, że jest to dodatnia liczba całkowita) i wielkość wszystkich rezerwacji. Może to być tablica, lista lub podobna struktura danych, jeśli Twój język obsługuje takie rzeczy. Wszystkie będą dodatnimi liczbami całkowitymi od 1 do n. Kolejność rezerwacji nie jest zdefiniowana ani nie jest ważna.

Wynik. Lista numerów rezerwacji pogrupowanych w ładunki tratwowe. Grupowanie musi być jednoznacznie wskazane, takie jak;

  • lista lub tablica tablic.
  • oddzielona przecinkami lista dla każdej tratwy. Nowa linia między każdą tratwą.

To, jak wdrożysz trzecią zasadę, zależy od ciebie, ale może to obejmować znalezienie średniego obłożenia tratwy i zminimalizowanie odchyleń od niej w jak największym stopniu. Oto kilka przypadków testowych.

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]

Obowiązują standardowe zasady, najkrótszy kod wygrywa. Baw się dobrze!

Edytowane; Sugerowany sposób zdefiniowania tak równo, jak to możliwe trzeciej zasady .

Po ustaleniu liczby tratw r(zgodnie z drugą zasadą), średnie obłożenie amożna obliczyć, sumując rezerwacje i dzieląc r. Dla każdej tratwy można znaleźć odchylenie od przeciętnego obłożenia za pomocą d(x) = abs(n(x)-a), gdzie n(x)jest liczba osób w każdej tratwie i 1 <= x <= r. Dla pewnej ciągłej funkcji o pojedynczej wartości f(y), która jest ściśle dodatnia i ma ściśle dodatnią pierwszą i nieujemną drugą pochodną dla wszystkich dodatnich y, definiujemy wielkość nieujemną Fjako sumę wszystkich f(d(x)), 1 <= x <= r. Każdy wybór przydziału tratw, który spełnia dwie pierwsze reguły i gdzie Fjest równy globalnemu minimum, spełni również trzecią zasadę.

Gwyn
źródło
3
W celu odniesienia w przyszłości możesz opublikować post w naszej piaskownicy, aby uzyskać opinię na temat wyzwania przed wysłaniem.
Wheat Wizard
Witamy w Programowaniu Puzzle i Code Golf! To wygląda na niezłe wyzwanie, wiedząc, że to twoje pierwsze wyzwanie. Jednak następnym razem lepiej może najpierw opublikować wyzwanie w piaskownicy , aby ludzie mogli tam podać sugestie. Następnie, gdy uważasz, że wyzwanie zostało wykonane, możesz opublikować je na głównej stronie. Dziękujemy za przeczytanie i życzę miłego dnia!
Matthew Roh
Jak mierzyć się tak równo, jak to możliwe ?
Dennis
@Dennis; Przedstawię sugerowany sposób zdefiniowania tego w edycji. Jeśli jednak masz inną metodę i możesz ją uzasadnić swoją odpowiedzią, to dobrze.
Gwyn
1
Pozostawienie sprawy do implementacji jest w porządku, o ile jasne jest, co jest ważne, a co nie, a twoja najnowsza edycja osiąga to imo. Jestem jednak nieco zaskoczony, że nie możemy użyć g(y) = y(drugiej pochodnej zero) lub g(y) = y²(pierwszej obniżenia zera kiedy y = 0).
Dennis

Odpowiedzi:

2

Perl 6 , 163 158 bajtów

{[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})}

Wypróbuj online!

Jak to działa

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

    Generuje wszystkie możliwe partycje wszystkich permutacji tablicy wejściowej.

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

    Filtruje te, w których żadna tratwa nie jest przepełniona.

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

    Filtruje te, w których liczba tratw jest minimalna.

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

    Pobiera pierwszy z minimalnym ∑ (n x -a) 2 .

-4 bajty dzięki @ Pietu1998

smls
źródło
Czy musisz to zrobić, .absjeśli wyrównasz wynik?
PurkkaKoodari
@ Pietu1998: Nie, dobry chwyt.
smls
3

Haskell 226 228 234 268 bajtów

Naiwna odpowiedź w 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

Lub bez golfa

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

Z niektórymi przypadkami testowymi

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

Gdzie testdaje

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

Edytować

Dzięki @flawr i @nimi za poradę.

pTrochę zgnieciony .

Ogoliłem kilka bajtów.

walpen
źródło
1
Można ustawić s=sum, a następnie użyć szamiast sum, a być może także zastąpić fst$ ...z ...!!0.
flawr
1
Można wymienić minimumBy(c s)z head.sortOn si usunąć funkcję c. Także: \t->sum t<=njest (<=n).sum.
nimi
@flawr, dobra sugestia, dzięki!
walpen
0

Python3, 224 bajty

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

Z walizkami testowymi:

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

Jak to działa?

pFunkcja po prostu generuje wszystkie partycje z danej listy (we wszystkich możliwych sposobów, aby podzielić go na podlist). s=sumpo prostu zmienia nazwę funkcji sumy, więc ostatni wiersz wykonuje całą pracę.

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.

Jestem pewien, że można dalej grać w golfa, zwłaszcza pfunkcję, ale pracowałem nad tym już od wielu godzin, więc proszę bardzo.

sagiksp
źródło