Я пытался сделать этот вопрос:
Даны три целых числа: GA, GB и GC (которые представляют яблоки, апельсины,
и бананы соответственно) & N строк, каждая из которых состоит из трех целых чисел:
А, В и С, которые представляют количество яблок, апельсинов и
бананы в этой еде соответственно.Проверьте, можно ли использовать только определенные коробки, чтобы общее
яблоки, апельсины и бананы в сумме составляют GA, Gb и GC соответственно. За
каждая доступная коробка, мы можем только выбрать купить ее или не покупать.
Он не может купить определенную коробку более одного раза, и он не может купить
дробное количество коробки.Образец теста
В
100 100 100 3 10 10 40 10 30 10 10 60 50
ИЗ
нет
В
100 100 100 5 40 70 30 30 10 40 20 20 50 10 50 90 40 10 20
ИЗ
да
Для этой проблемы я написал некоторый код, но получаю только ошибки сегментации и ряд ошибок. Плюс мой алгоритм довольно плохой. Что я делаю, так это нахожу все подмножества массива яблок таким образом, чтобы их сумма составляла GA, а затем проверяю, есть ли в этих наборах апельсины и бананы для добавления в GB и GC. Но эта идея довольно медленная и очень сложная для кодирования …
Я полагаю, что это в некоторой степени разновидность проблемы с рюкзаком, и ее можно решить с большей сложностью (по крайней мере, лучше, чем O (2 ^ N) [Моя текущая сложность]; P). Итак, что будет лучшим алгоритмом для решения этого вопроса, а также см. Мой текущий код на Pastebin(Я не помещал код в stackoverflow, потому что он некорректен, и, более того, я считаю, что мне придется начинать с нуля с ним …)
Это вариант 0-1 рюкзак проблема. Эта проблема является NP-трудной, поэтому нет надежды найти решение за полиномиальное время, но существует решение в псевдо-полином время, которое делает эту проблему довольно легкой (в мире сложных проблем).
Алгоритм работает следующим образом:
<0,0,0>
,<a',b',c'>
: перебрать все кортежи <a,b,c>
в коллекции и добавить <a+a',b+b',c+c'>
в коллекцию, убедитесь, что дубликаты не добавляются. Не добавляйте кортежи, где один или несколько элементов имеют превышено соответствующее целевое значение.Необязательно, но настоятельно рекомендуется нижний предел исключения: вы также можете выполнить предпросмотр и, например, исключить все значения, которые никогда не достигнут заданной цели (скажем, вы можете добавить 20
яблоки то все значения меньше чем 80
яблоки можно уничтожить).
Концепция 1 (Нижняя граница): Так как вы добавляете значения кортежей вместе, вы теперь, если есть кортежи
<a0,a1,a2>
а также<b0,b1,b2>
оставив, добавив их, можно максимально увеличить кортеж с<a0+b0,a1+b1,a2+b2>
, Теперь скажите, что цель<t0,t1,t2>
тогда вы можете безопасно удалить кортеж<q0,q1,q2>
еслиq0+a0+b0 < t0
(обобщить на другие элементы кортежей), поскольку, даже если вы можете добавить последние кортежи, он никогда не достигнет требуемых значений. Таким образом, нижняя граница<t0-a0-b0,t1-a1-b1,t2-a2-b2>
, Вы можете обобщить это для N кортежи.
Итак, сначала вы сложите все предоставленные кортежи вместе (для второго случая это <140,160,230>
) и затем вычесть это из цели (результат, таким образом: <-40,-60,-130>
). На каждой итерации нижняя граница увеличивается с этой коробкой, поэтому после первой итерации результат для второго примера равен (<-40+40,-60+70,-130+30>
или же <0,10,-100>
).
Однако сложность времени O (та ^ 3 тб ^ 3 тс ^ 3) с та, Т.Б. а также дц целевые значения.
Пример 1 (высокий уровень по двум заданным тестам):
ВХОД
100 100 100
3
10 10 40
10 30 10
10 60 50
Набор начинается с {<0,0,0>}
после каждой итерации получаем:
{<0,0,0>}
;{<0,0,0>,<10,10,40>}
;{<0,0,0>,<10,10,40>,<10,30,10>,<20,40,50>}
; а также{<0,0,0>,<10,10,40>,<10,30,10>,<20,40,50>,<10,60,50>,<10,60,50>,<20,70,90>,<30,100,100>}
Таким образом, провал.С underbound-элиминирования:
{<0,0,0>}
, нижняя граница <100-30,100-100,100-100>=<70,0,0>
таким образом устранить <0,0,0>
,{}
таким образом распечатать «Нет».Пример 2
ВХОД
100 100 100
5
40 70 30
30 10 40
20 20 50
10 50 90
40 10 20
С нижний предел исключения:
{<0,0,0>}
нижняя граница: <-40,-60,-130>
таким образом, хорошо.{<0,0,0>,<40,70,30>}
нижняя граница: <0,10,-100>
(Устранить <0,0,0>
потому что вторые конфликты).{<40,70,30>,<70,80,70>}
нижняя граница: <30,20,-60>
(без исключения).{<40,70,30>,<70,80,70>,<60,90,80>,<90,100,120>}
нижняя граница: <50,40,-10>
(Устранить <40,70,30>
) верхнее устранение <90,100,120>
,{<70,80,70>,<60,90,80>,<80,130,160>,<70,140,170>}
нижняя граница: <60,90,80>
(Устранить <70,80,70>
) верхнее устранение <80,130,160>
а также <70,140,170>
,{<60,90,80>,<100,100,100>}
нижняя граница: <100,100,100>
(Устранить <60,90,80>
).{<100,100,100>}
таким образом «да».Программа на Haskell
Я реализовал (не очень эффективную, но проверенную концепцию) программу на Haskell, которая добивается цели произвольной длины кортежа:
import qualified Data.Set as Set
tupleSize :: Int
tupleSize = 3
group :: Int -> [a] -> [[a]]
group _ [] = []
group n l = take n l : group n (drop n l)
empty :: Int -> Set.Set [Int]
empty n = Set.fromList [replicate n 0]
solve :: [Int] -> [[Int]] -> Bool
solve t qs = Set.member t $ mix t (lowerBound t qs) qs $ empty $ length t
lowerBound :: [Int] -> [[Int]] -> [Int]
lowerBound = foldl (zipWith (-))
lowerCheck :: [Int] -> [Int] -> Bool
lowerCheck l x = and $ zipWith (<=) l x
targetCheck :: [Int] -> [Int] -> Bool
targetCheck t x = and $ zipWith (>=) t x
takeout :: Int -> [a] -> [a]
takeout _ [] = []
takeout i (h:hs) | i == 0 = hs
| otherwise = h : takeout (i-1) hs
mix :: [Int] -> [Int] -> [[Int]] -> Set.Set [Int] -> Set.Set [Int]
mix _ _ [] s = s
mix t l (q:qs) s = mix t (zipWith(+) l q) qs $ Set.filter (lowerCheck l) $ Set.union s $ Set.filter (targetCheck t) $ Set.map (zipWith (+) q) s
reply :: Bool -> String
reply True = "yes"reply False = "no"
main = interact $ \x -> let tuples = group tupleSize $ takeout tupleSize $ map read (words x) in reply $ solve (head tuples) (tail tuples)
Вы можете скомпилировать запустить его, используя:
ghc file.hs
./file < input
Заключение: Хотя поведение в худшем случае может быть сложным, второй пример показывает, что проблему можно решить эффективно в некоторых случаях.
Ошибки сегментации — полностью ваша проблема.
Рюкзак является NP-полным, и это тоже самое (предположим, что входные данные, где A, B, C всегда одинаковы, а Ga = половина суммы A). Я не думаю, что кто-то просит вас решить проблемы NP-здесь.
Очевидно, вы проверяете не все наборы, а только те с суммой A <= 100, сумма B <= 100, сумма С <= 100.
Та же ситуация, что и с этим вопрос.
Этот вопрос является второй проблемой из Facebook Hackercup отборочный раунд, который В настоящее время в процессе (это закончится 12 января 12:00 UTC).
Здесь не совсем справедливо просить решения проблем соревнований по активному программированию.