2012-01-17 3 views
5

У меня есть список products, который состоит из списка shops, который продал его.Алгоритм минимизации корзины покупок

{ 
    'Book A': [ShopA, ShopB, ShopC], 
    'Book B': [ShopC, ShopD], 
    'Movie C': [ShopA, ShopB, ShopD, ShopE], 
    ... 
} 

(цена отличается между магазинами)

Каждый магазин также имеет стоимость доставки. Это стоимость доставки «за заказ», неважно, сколько предметов в моей корзине. И он также отличается от магазинов.

Ex: если я покупаю "Book A" от ShopA, "Книга B" от ShopC и "Movie C" из ShopA, результирующая цена: Book A price in ShopA + Book B price in ShopC + Movie C price in ShopA + ShopC shipping cost + ShopA shipping cost

Если стоимость доставки была равна нулю или она была по-позиции и постоянна, я просто сортировал списки предложений на поле price+shipping и получал первый результат из каждого набора.

мне нужно купить все элементы раз и найти минимальную цену и результирующий набор.

Я не очень хорошо разбираюсь в алгоритмах оптимизации и динамическом программировании, поэтому мне нужно решение или просто кивка в правильном направлении.

+0

Можете ли вы дать некоторые оценки количества магазинов и продуктов, которые вам понадобятся для обработки. В настоящее время я придумал алгоритм, который хорошо работает только для очень небольшого количества продуктов, и у меня такое ощущение, что это не так ... –

+0

5-10 предметов, 30-50 магазинов – dmzkrsk

+0

Для любви к Богу, пожалуйста, реализуйте это. Это то, что я больше всего ненавижу в таких сайтах, как Amazon: не только заранее не знаю стоимость доставки, но я действительно не знаю, будут ли они отправляться на определенный адрес ** вообще **, пока я не получу проверку. – Groo

ответ

3

С такими маленькими предметами у меня есть решение. Это динамично.

Мы будем обрабатывать каждый магазин итеративно. На каждом шагу мы сохраняем текущую лучшую цену, с которой мы можем покрыть все подмножества элементов. В начале все они - infinity в цене, за исключением пустого подмножества, которое составляет 0. Обратите внимание, что все подмножества: 2^Num_products, но в вашем случае это всего около 1000.

Теперь, как мы обрабатываем следующий магазин: подумайте, что вы покрываете все возможные подмножества продуктов этим магазином (я имею в виду подмножество, которое магазин действительно может обеспечить), а все остальные продукты покрываются магазинами, которые вы уже наблюдали, тем самым улучшая минимальные затраты на покрытие всех подмножеств. Этот шаг занимает 2^Num_products*2^Num_products=4^Num_products, все еще около миллиона, который голый. Вы делаете это для каждого магазина, и в конце ответ - это стоимость покрытия всех элементов. Вся сложность предлагаемого решения составляет 4^Num_products * num_shops, что составляет около 50 миллионов, что хорошо.

Обратите внимание, что это все еще экспоненциально, и это неудивительно. Благодарим вас за невероятное доказательство NP.

EDIT Добавление дополнительного объяснения алгоритма в псевдокоде:

init: 
cost[subset] = infi 
cost[{}] = 0 
for shop in shops 
new_prices = costs.dup() 
for set : subsets 
    for covered_set : all_subsets(set) 
    price = covered_set == {} ? 0 : delivery[shop] 
    remaining = set 
    for element : covered_set 
     if shop do not sale element 
     break for, choose next covered_set 
     price += el_price[element] 
     remaining.remove(element) 
    price += costs[remaining] 
    new_prices[set] = min(new_prices[set], price) 
costs = new_prices 
return costs[all] 

Заметим, что здесь я использую наборы как индекс - это потому, что я на самом деле использовать битовую представление подмножеств, например, 1101 представляет собой подмножество, содержащее 1-го, 2-го и четвертого элементов. Таким образом, итерация всех наборов равна for (int i = 0; i < (1 << n); i++).

Существует и еще одна вещи: если вы хотите, чтобы цикл всех подмножеств подмножества S вы на самом деле можете сделать это быстрее, чем итерация всех подмножеств исходного набора и проверкой подмножеством является ли подмножество S. Если S также представлено с битовой маской bit_mask, это для цикла выполняет задание: for(int i = bit_mask; i > 0; i = (i - 1) & bitmask). Используя этот подход, вы уменьшаете сложность алгоритма до 3^Num_products * num_shops. Тем не менее, это немного сложнее понять, и вам, вероятно, потребуется написать вручную один пример, чтобы убедиться, что цикл, который я написал, фактически циклически выполняет все подмножества S. О сложности - просто поверьте мне.

EDIT2 Отредактировано состояние перерыва.также позвольте мне подробно рассказать о наборе remaining и его вычислении: как dmzkrsk указал, что псевдокод упоминает удаление из набора, но на самом деле вы можете просто назначить remaining = set^covered_set (снова операцию бит) в случае использования битмасков для представления подмножеств.

+0

Мне все еще не совсем понятно. Не могли бы вы предоставить псевдокод или выполнить шаги на небольшом книжном магазине? – dmzkrsk

+0

Сделано, скажите, если вам нужно больше объяснений в представлении подмножества. –

+0

Ну, я реализовал это и, похоже, работает. У меня есть только два вопроса: 1) если 'set' и' cover_set' - битмаски, то 'оставаясь' просто равными' set-coated_set', поэтому нам не нужна логика 'Остальная.ремонт'? 2) 'break for onpass_set' означает, что мы переходим к следующему' cover_set' в 'для cover_set: all_subsets (set)' loop или отказываемся от этого цикла и переходим к следующему набору в 'for set: subsets'? – dmzkrsk

3

Эта проблема NP Hard.
Мы покажем сокращение от Hitting Set problem.
ударяя Поставленная задача: С учетом множества S1,S2,...,Sn и ряд k: выбрал установить S размера k, таким образом, что для каждого Si есть элемент s в S таким образом, что s в Si. [альтернативное определение: пересечение между Si и S не пусто].

Уменьшение:
Учитывая экземпляр удара набор в виде (S1,...,Sn,k) создать экземпляр этой проблемы:

All books cost nothing. In order to buy from each store you pay 1. 
The book i is sold by each store denoted in Si, minimal price for this instance is k. 

доказательство:
ударяя Set -> Эта проблема : Предположим, что существует минимальный набор ударов в (S1,...,Sn) размера k. Пусть этот набор удалений будет S. Покупая из каждого магазина в S, мы можем купить все наши книги по цене k, так как книги ничего не стоят [в нашей конструкции], и мы купили все книги, и мы заплатили за заказы от магазинов точно k, таким образом общая цена был k.
Эта проблема -> Комплект для установки: Если у вас возникли проблемы с ценой k. Затем из здания проблемы, а так как книги ничего не стоят, нам нужно купить в магазинах k разные магазины, чтобы получить все книги. Пусть эти магазины будут S.Из конструкции проблемы S является ударным набором для (S1,...,Sn)
Q.E.D.

Вывод:
Таким образом, эта проблема «не легче, чем» ударяя Поставленная задача, и нет никакого известного полиномиальное решение этой проблемы, так - ваш лучший снимок, если вы хотите оптимальное решение, вероятно, является экспоненциальный, такой как backtracking [Проверить все возможности и вернуть минимальное решение].

+0

Ваш комментарий замечательный, плохой я не могу принять – dmzkrsk

0

Хорошей эвристикой может быть оптимизация колонии муравьев. Я использую его для решения проблемы продавцов. Вы можете найти рабочий пример из google tsp solver. Это библиотека javascript, которая также использует грубую силу и динамическое программирование. AOC используется, когда у вас есть больше городов для вычисления текущего лимита в 20 городах. Я считаю, что вы можете использовать библиотеку для решения своей проблемы, и ей просто нужно немного переписать. В 20 городах программа должна проверить 20! posibilites. В вашем случае это немного легче, но, возможно, только величина.

1

Однажды я столкнулся с этой точной проблемой. Я не придумал другого решения, кроме как проверять все возможные комбинации магазинов, но есть простой способ отфильтровать многие магазины в каждом продукте.

1. Рассчитать самую низкую цену (включая стоимость доставки) каждого продукта, назовем ее best_price.

2. В каждом продукте, оставить только магазины, где цены магазина (без стоимости доставки) < = best_price (со стоимостью доставки)

3. испытания все возможные комбинации магазинов для самый дешевый.

Смежные вопросы