Проблема з сплавом на рафті (варіант рюкзака)


20

Перша головоломка від мене, пропозиції щодо вдосконалення з радістю отримали!

Сценарій такий; Ви працюєте менеджером по рафтинговій компанії. Щоранку вам подають список бронювання, і вам доведеться сортувати їх за плотними навантаженнями. Напишіть програму або функцію на обраній вами мові, яка робить це за вас.

Кожен пліт має максимум nклієнтів, і кожне бронювання призначене для групи від 1 до nлюдей (включно). Необхідно дотримуватися наступних правил;

  • Жодна група не може бути розділена. Якщо вони забронювали разом, вони повинні бути на одному плоті.

  • Кількість плотів необхідно мінімізувати.

  • При дотриманні двох попередніх правил групи повинні бути розподілені якомога рівномірно між плотами.

Вхідні дані. Кількість 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), яка є строго позитивною і має строго позитивну першу і негативну другу похідні для всіх позитивних y, ми визначаємо негативну величину Fяк суму всіх значень f(d(x)), 1 <= x <= r. Будь-який вибір розподілу плотів, який відповідає першим двом правилам, і де Fдорівнює глобальному мінімуму, задовольняє і третє правило.


3
Для подальшої довідки ви можете опублікувати в нашій пісочниці, щоб отримати відгук про виклик, перш ніж публікувати.
Пшеничний майстер

Ласкаво просимо до головоломки програмування та коду для гольфу! Це виглядає як приємний виклик, знаючи, що це ваш перший виклик. Наступного разу, однак, може бути краще спочатку опублікувати виклик у « Пісочниці» , щоб люди могли давати пропозиції там. Тоді, коли ви вважаєте, що виклик виконано, ви можете опублікувати його на головному сайті. Дякую за прочитання та приємного дня!
Метью Рох

Як вимірюється якомога рівномірніше ?
Денніс

@Dennis; Я запропону запропонований спосіб визначити це в редагуванні. Однак якщо у вас інший метод і ви можете виправдати це своєю відповіддю, це добре.
Гвін

1
Залишати речі до реалізації добре, якщо зрозуміло, що є дійсним, а що ні, і остання редакція досягне цього іммо. Я трохи переконався, що ми не можемо використовувати g(y) = y(другий похідний нуль) або 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 .

-4 байти завдяки @ Pietu1998


Чи потрібно робити, .absякщо результат квадратний?
PurkkaKoodari

@ Pietu1998: Не знаю, добрий лов.
smls

3

Haskell 226 228 234 268 байт

Наївна відповідь у Хаскеллі

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.
недолік

1
Ви можете замінити minimumBy(c s)з head.sortOn sі видалити функцію c. Також: \t->sum t<=nє (<=n).sum.
німі

@flawr, хороша пропозиція, дякую!
проходити

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функція, але я над цим працював уже годинами, тож ось ти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.