Алгоритм ветвления для задачи о рюкзаке (или "задача о рюкзаке 0/1") помогает определить, какие предметы следует выбрать для максимизации общей стоимости при ограниченном размере рюкзака. Суть задачи заключается в том, что у нас есть набор предметов, каждый из которых имеет определённый вес и стоимость, и нам нужно выбрать некоторые из них так, чтобы их общий вес не превышал заданного лимита.
Определение задачи
Входные данные:
- Набор предметов, каждый из которых имеет вес ( w_i ) и стоимость ( c_i ).
- Максимальный вес рюкзака ( W ).
Выходные данные:
- Набор выбранных предметов, максимальная стоимость которых не превышает ( W ).
Алгоритм ветвления (Branch and Bound)
Структура данных:
- Создайте структуру данных для хранения предметов. Например, можно использовать массив объектов, где каждый объект содержит вес и стоимость предмета.
- Определите переменные для хранения текущей максимальной стоимости, текущего веса и выбранных предметов.
Сортировка предметов:
- Для оптимизации можно предварительно отсортировать предметы по убыванию их стоимости на единицу веса (отношение ( c_i/w_i )).
Рекурсивная функция:
- Создайте рекурсивную функцию, которая будет принимать текущий индекс предмета, текущий вес и текущую стоимость.
Условия ветвления:
- Если текущий вес превышает ( W ), вернитесь (это ветвь не подходит).
- Если текущий индекс равен количеству предметов, проверьте, является ли текущая стоимость максимальной, и обновите её при необходимости.
- В противном случае:
- Ветвь без включения текущего предмета: вызовите рекурсивную функцию для следующего предмета.
- Ветвь с включением текущего предмета: добавьте вес и стоимость текущего предмета и вызовите рекурсивную функцию для следующего предмета.
Проверка и обновление максимальной стоимости:
- После завершения рекурсии проверьте, была ли найдена новая максимальная стоимость, и обновите соответствующие переменные.
Пример кода на Python
Вот пример простого алгоритма ветвления для задачи о рюкзаке:
class Item:
def __init__(self, weight, value):
self.weight = weight
self.value = value
def knapsack(items, capacity):
n = len(items)
max_value = 0
best_combination = []
def branch_and_bound(index, current_weight, current_value, selected_items):
nonlocal max_value, best_combination
if current_weight > capacity:
return
if index == n:
if current_value > max_value:
max_value = current_value
best_combination = selected_items[:]
return
# Ветвь без текущего предмета
branch_and_bound(index + 1, current_weight, current_value, selected_items)
# Ветвь с текущим предметом
selected_items.append(items[index])
branch_and_bound(index + 1, current_weight + items[index].weight, current_value + items[index].value, selected_items)
selected_items.pop()
branch_and_bound(0, 0, 0, [])
return max_value, best_combination
# Пример использования
items = [Item(2, 3), Item(3, 4), Item(4, 5), Item(5, 6)]
capacity = 5
max_value, best_combination = knapsack(items, capacity)
print(f"Максимальная стоимость: {max_value}")
print("Выбранные предметы:")
for item in best_combination:
print(f"Вес: {item.weight}, Стоимость: {item.value}")
Заключение
Этот алгоритм позволяет эффективно решать задачу о рюкзаке с использованием метода ветвления и границ. Он может быть оптимизирован различными способами, включая использование жадных подходов, динамического программирования и других алгоритмических техник, в зависимости от конкретных требований и ограничений задачи.