Комбинированная оптимизация в Python

Мне нужно собрать продукты со складских центров для комплектации продуктов вот так {продукт:количество} center_a_products = {1: 8, 2: 4, 3: 12}

Каждый центр имеет различные виды и количество продуктов вот так {center:{product:quantity}} product_quantities = {1: {1: 10, 2: 3, 3: 15}, 2: {1: 5, 2: 8, 3: 10}, 3: {1: 12, 2: 6}}

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

Я пробовал это, но это не удалось...

from itertools import combinations

# Define the centers
centers = [1, 2, 3]

# Define the products and quantities needed in Center A
center_a_products = {
    1: 8,
    2: 4,
    3: 12
}

# Define the products and quantities for each center
product_quantities = {
    1: {1: 10, 2: 3, 3: 15},
    2: {1: 5, 2: 8, 3: 10},
    3: {1: 12, 2: 6}
}

# Function to check if a product combination meets the requirements
def meets_requirements(combination):
    product_counts = {product: 0 for product in center_a_products.keys()}
    for center, products in combination:
        for product, quantity in products.items():
            product_counts[product] += quantity
    for product, required_quantity in center_a_products.items():
        if product_counts[product] < required_quantity:
            return False
    return True

# Find all combinations of products
combinations_to_move = []
for r in range(1, len(centers) + 1):
    for combination in combinations(zip(centers, [product_quantities[c] for c in centers]), r):
        if meets_requirements(combination):
            combinations_to_move.append(combination)

# Print the combinations
for idx, combination in enumerate(combinations_to_move, start=1):
    print(f"Combination {idx}:")
    for center, products in combination:
        for product, quantity in products.items():
            print(f"Move {quantity} units of product {product} from Center {center}")

Я ожидал чего-то подобного

Move 8 units of product 1 from Center 1
Move 3 units of product 2 from Center 1
Move 12 units of product 3 from Center 1
Move 1 units of product 3 from Center 2

Если код был сгенерирован ChatGPT, имейте в виду, что публикация такого контента (не только ответов) в настоящее время не разрешена

Michael Butscher 03.07.2023 13:31

Спасибо, что дали мне знать! буду переделывать!

user22167296 03.07.2023 14:12

Я не понимаю, в чем сложность для примера, который вы привели. центр А - это то, что вам нужно, и количество на разных складах? Для примера, который вы предоставили, просто перейдите в центр 1, у него есть все как 10> 8, 5> 4 и 15> 12. пожалуйста, предоставьте более сложный пример и ожидаемый результат

Sebastian Wozny 03.07.2023 14:24

похоже, вы решаете вариант задачи коммивояжера

Mark 03.07.2023 14:33

Это просто, потому что это образец данных, мой фактический центр, продукт, количество намного сложнее

user22167296 04.07.2023 05:16
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
5
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Описание проблемы поддается решению с помощью Смешанной целочисленно-линейной программы (MIP).

Удобная библиотека для решения смешанных целочисленных задач — PuLP , которая поставляется со встроенным набором Coin-OR и, в частности, целочисленным решателем CBC.

Сформулируем модель, описывающую вашу проблему:

import pulp


center_a_products = {
    1: 8,
    2: 4,
    3: 12
}

product_quantities = {
    1: {1: 10, 2: 5, 3: 15},
    2: {1: 5, 2: 8, 3: 10},
    3: {1: 12, 2: 6, 3: 20}
}

problem = pulp.LpProblem("CenterSatisfactionProblem", pulp.LpMinimize)

# Center vars are binary variables that we minimize in the objective. They indicate whether a center was visited or not
center_vars = {center: pulp.LpVariable(f"Center_{center}", cat = "Binary") for center in product_quantities}
product_vars = {(center, product): pulp.LpVariable(f"Center_{center}_Product_{product}", lowBound=0, cat = "Integer")
                for center in product_quantities
                for product in product_quantities[center]}


# Satisfy all demand
for product in center_a_products:
    problem += pulp.lpSum(product_vars[center, product] for center in product_quantities) == center_a_products[product]

# We can only take stuff from a center if we visit it 
# Also: can't take more stuff from a center than is in stock

for center in product_quantities:
    for product in product_quantities[center]:
        problem += product_vars[center, product] <= center_vars[center] * product_quantities[center][product]
# Minimize amount of centers visited
problem += pulp.lpSum(center_vars.values())
problem.solve()

Решение для печати:

for center in product_quantities:
    if center_vars[center].varValue == 1:
        for product in product_quantities[center]:
            quantity = product_vars[center, product].varValue
            if quantity > 0:
                print(f"Move {quantity} units of product {product} from center {center}")

Выход:

Move 8.0 units of product 1 from center 3
Move 4.0 units of product 2 from center 3
Move 12.0 units of product 3 from center 3

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

Преобразование описания проблемы в линейную программу может потребовать некоторой практики. Самая сложная строка в этой программе

problem += product_vars[center, product] <= center_vars[center] * product_quantities[center][product]

Цель минимизирует center_vars, но ограничение удовлетворения заставляет некоторые из них быть равными 1.

Чтобы научиться описывать проблемы, а не думать о решениях, я рекомендую отличный доклад Рэймонда Хеттингера на PyCon 2019 — Современные решатели: четко определенные проблемы — это решенные проблемы

установить PuLP

pip install pulp

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

user22167296 04.07.2023 05:04

Другие вопросы по теме