Проблема рафтинга (рюкзак)

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
Для дальнейшего использования вы можете написать в нашу песочницу, чтобы получить отзыв о конкурсе, прежде чем отправлять.
Пшеничный волшебник
Добро пожаловать в Программирование Пазлов и Code Golf! Это похоже на хороший вызов, зная, что это ваш первый вызов. В следующий раз, однако, может быть, лучше сначала опубликовать задание в Песочнице , чтобы люди могли давать предложения там. Затем, когда вы думаете, что задача выполнена, вы можете опубликовать ее на главном сайте. Спасибо за чтение, и хорошего дня!
Мэтью Ро
Как измеряется в равной степени ?
Деннис
@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

SMLS
источник
Вам нужно сделать, .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немного.

Сбрил пару байтов.

walpen
источник
1
Вы можете установить, s=sumа затем использовать sвместо sum, и, возможно, вы могли бы также заменить fst$ ...на ...!!0.
flawr
1
Вы можете заменить minimumBy(c s)с head.sortOn sи удалить функцию c. Также: \t->sum t<=nесть (<=n).sum.
Ними
@ 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просто переименовывает функцию 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функция, но я работал над этим уже часами, так что здесь вы идете.

sagiksp
источник