Rafting Problem (variante zaino)


20

Primo puzzle da parte mia, suggerimenti di miglioramento accolti volentieri!

Lo scenario è; Lavori come manager per una compagnia di rafting in acque bianche. Ogni mattina ti viene fornito un elenco di prenotazioni e devi ordinarle in carichi di zattera. Scrivi un programma o una funzione nella lingua che hai scelto per te.

Ogni zattera detiene un massimo di nclienti e ogni prenotazione è per un gruppo compreso tra 1 e npersone (incluso). Devono essere rispettate le seguenti regole;

  • Nessun gruppo può essere diviso. Se hanno prenotato insieme, devono essere tutti nella stessa zattera.

  • Il numero di zattere deve essere ridotto al minimo.

  • Fatte salve le due regole precedenti, i gruppi devono essere distribuiti il ​​più equamente possibile tra le zattere.

Ingressi. Il numero n(si può presumere che si tratti di un numero intero positivo) e la dimensione di tutte le prenotazioni. Questo può essere un array, un elenco o una struttura di dati simile se la tua lingua supporta tali elementi. Tutti questi saranno numeri interi positivi tra 1 e n. L'ordine delle prenotazioni non è definito, né è importante.

Produzione. Un elenco dei numeri di prenotazione, raggruppati in carichi zattera. Il raggruppamento deve essere indicato in modo inequivocabile, ad esempio;

  • un elenco o una matrice di array.
  • un elenco separato da virgole per ogni zattera. Newline tra ogni zattera.

Il modo in cui implementate la terza regola dipende da voi, ma ciò potrebbe comportare la ricerca dell'occupazione media della zattera e la riduzione al minimo delle deviazioni da essa. Ecco alcuni casi di test.

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]

Si applicano le regole standard, vince il codice più breve. Divertiti!

Modificato; Un modo suggerito per definire il più equamente possibile per la terza regola.

Una volta determinato il numero di zattere r(soggetto alla seconda regola), l'occupazione media apuò essere calcolata sommando le prenotazioni e dividendo per r. Per ogni zattera, la deviazione dall'occupazione media può essere trovata usando d(x) = abs(n(x)-a), dove n(x)è il numero di persone in ogni zattera e 1 <= x <= r. Per alcune funzioni continue a valore singolo f(y), che sono strettamente positive e hanno un primo derivato rigorosamente positivo e secondi non negativi per tutti i positivi y, definiamo una quantità non negativa F, come la somma di tutti i f(d(x)), 1 <= x <= r. Qualsiasi scelta di allocazione della zattera che soddisfi le prime due regole e dove Fsia uguale al minimo globale soddisferà anche la terza regola.


3
Per riferimento futuro puoi pubblicare sul nostro sandbox per ricevere feedback su una sfida prima di pubblicare.
Wheat Wizard

Benvenuto in Programmazione di puzzle e codice golf! Sembra una bella sfida, sapendo che è la tua prima sfida. La prossima volta, tuttavia, potrebbe essere meglio pubblicare prima la sfida nella Sandbox , in modo che le persone possano dare suggerimenti lì. Quindi, quando pensi che la sfida sia terminata, puoi pubblicarla sul sito principale. Grazie per aver letto e buona giornata!
Matthew Roh,

Come viene misurato il più equamente possibile ?
Dennis,

@Dennis; Metterò un modo suggerito per definirlo in una modifica. Tuttavia, se hai un metodo diverso e puoi giustificarlo per la tua risposta, va bene.
Gwyn,

1
Lasciare le cose fino all'implementazione va bene, purché sia ​​chiaro ciò che è valido e cosa no, e la tua ultima modifica raggiunge quell'immo. Sono un po 'sorpreso che non possiamo usare g(y) = y(secondo zero derivato) o g(y) = y²(primo derviato zero quando y = 0) però.
Dennis,

Risposte:


2

Perl 6 , 163 158 byte

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

Provalo online!

Come funziona

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

    Genera tutte le possibili partizioni di tutte le permutazioni dell'array di input.

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

    Filtra quelli in cui nessuna zattera è prenotata in eccesso.

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

    Filtra quelli in cui il numero di zattere è minimo.

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

    Ottiene il primo con il minimo ∑ (n x -a) 2 .

-4 byte grazie a @ Pietu1998


Hai bisogno di fare .absse quadrate il risultato?
PurkkaKoodari,

@ Pietu1998: no, buona cattura.
smls,

3

Haskell 226 228 234 268 byte

Risposta ingenua in 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

O non golfato

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

Con alcuni casi di test

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

Dove testcede

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

modificare

Grazie a @flawr e @nimi per un consiglio.

Schiacciato pun po '

Rasato un paio di byte.


1
È possibile impostare s=sume quindi utilizzare al sposto di sum, e forse è anche possibile sostituire fst$ ...con ...!!0.
Flawr,

1
È possibile sostituire minimumBy(c s)con head.sortOn se rimuovere la funzione c. Inoltre: \t->sum t<=nè (<=n).sum.
nimi,

@flawr, buon suggerimento, grazie!
walpen

0

Python3, 224 byte

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

Con le prove:

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

Come funziona?

La pfunzione genera semplicemente tutte le partizioni di un determinato elenco (tutti i modi possibili per dividerlo in elenchi secondari). s=sumrinomina semplicemente la funzione di somma, quindi l'ultima riga fa tutto il lavoro.

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.

Sono certo che questo può essere ulteriormente approfondito, in particolare la pfunzione, ma ci ho già lavorato per ore, quindi eccoti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.