Задача рюкзака
Задача рюкзака
Задача рюкзака
Задача рюкзака — это оптимизационная задача, в которой нужно определить, какие предметы положить в рюкзак (ранец) ограниченной вместимости, чтобы максимизировать суммарную стоимость. Предметы могут быть как целыми, так и дробными. В этой главе мы рассматриваем только целочисленный вариант (0/1 knapsack), поскольку дробный вариант решается жадно.
Постановка:
Дано предметов, каждый имеет вес и стоимость, и рюкзак вместимостью (). Нужно выбрать некоторые предметы так, чтобы их суммарный вес не превышал , а суммарная стоимость была максимальной. Предметы нельзя делить на части.
Пример: при , и предметах
, ,
(первое число — стоимость, второе — вес)
можно получить максимальную стоимость , положив в рюкзак и (вес ).
Для решения и отслеживания максимальной стоимости будем вести двумерный массив dp, где:
dp[i][w] — максимальная стоимость, которую можно получить, используя первые предметов при ограничении веса .То есть состояние — это пара :
i означает, что рассматриваем предметы ;w — текущий лимит по весу.dp[0][w] = 0, так как предметов нет.dp[i][0] = 0, так как вес рюкзака равен нулю.Рассматриваем предмет (индексация с 1), у него:
value[i-1],weight[i-1].На весе w есть два варианта:
dp[i][w] = dp[i - 1][w].weight[i - 1] <= w): тогдаdp[i][w] = value[i - 1] + dp[i - 1][w - weight[i - 1]].Берём максимум из этих вариантов.
int knapsack(const vector<int>& weights, const vector<int>& values, int capacity) {
int n = (int)weights.size();
vector<vector<int>> dp(n + 1, vector<int>(capacity + 1, 0));
for (int i = 1; i <= n; i++) {
for (int w = 0; w <= capacity; w++) {
dp[i][w] = dp[i - 1][w]; // не берем предмет i
if (weights[i - 1] <= w) { // берем предмет i
dp[i][w] = max(dp[i][w],
values[i - 1] + dp[i - 1][w - weights[i - 1]]);
}
}
}
return dp[n][capacity];
}