knapsack problem (tsz. knapsack problems)
A hátizsák probléma (angolul Knapsack Problem) egy klasszikus kombinatorikus optimalizálási probléma, amely gyakran előfordul az informatikában, műveletek kutatásában, gazdaságban és más alkalmazott tudományokban. A probléma lényege, hogy adott egy hátizsák, amelynek adott a teherbírása (kapacitása), és több különböző tárgy, amelyeknek van súlya és értéke. A cél az, hogy a tárgyak egy részét úgy válasszuk ki, hogy a hátizsák kapacitását ne lépjük túl, és az összérték maximális legyen.
Legyen:
Célfüggvény:
Korlátozás:
Ez az ún. 0-1 hátizsák probléma, mivel minden tárgyból csak egy példány választható (nem darabolható).
A hátizsák problémának több változata is ismert:
Tegyük fel, hogy van egy 10 kg kapacitású hátizsákod, és az alábbi tárgyak közül választhatsz:
Tárgy | Súly (kg) | Érték (Ft) |
---|---|---|
A | 2 | 3000 |
B | 3 | 3500 |
C | 5 | 8000 |
D | 4 | 4500 |
A cél: olyan kombinációt találni, amely nem haladja meg a 10 kg-ot, és az összérték maximális.
Az összes kombinációt kipróbáljuk. Ez kis -re működik, de nagy számú tárgy esetén exponenciális idejű és gyakorlatilag használhatatlan.
Hatékony módszer 0-1 hátizsák problémára. Egy kétdimenziós táblát használunk: jelenti a maximális értéket az első tárgyból választva, ha a hátizsák kapacitása .
Rekurzió:
Időkomplexitás:
Frakcionált esetben (amikor a tárgyak darabolhatók), a válogató módszer (greedy) a legjobb.
Lépések:
Ez a módszer optimális frakcionált esetben, de nem működik 0-1 esetben!
A döntési fa mentén végigjárjuk a lehetőségeket, de visszalépünk (cut), ha már nem lehet jobb eredményt elérni. Ez okos keresés kimerítő próbálkozás helyett.
Nagy méretű problémákhoz:
Ezek nem garantálnak optimális megoldást, de nagy problémákra jó közelítő megoldást adnak gyorsan.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int knapsack(int C, vector<int>& weights, vector<int>& values, int n) {
vector<vector<int>> dp(n+1, vector<int>(C+1, 0));
for (int i = 1; i <= n; ++i) {
for (int w = 0; w <= C; ++w) {
if (weights > w)
dp = dp;
else
dp = max(dp, dp] + values);
}
}
return dp;
}
int main() {
vector<int> weights = {2, 3, 5, 4};
vector<int> values = {3000, 3500, 8000, 4500};
int capacity = 10;
int n = weights.size();
cout << "Max érték: " << knapsack(capacity, weights, values, n) << " Ft" << endl;
}
A hátizsák probléma egy NP-teljes probléma, azaz nincs ismert polinomiális idejű algoritmus, amely minden esetben garantáltan megoldja. Ugyanakkor kis méretű példákra dinamikus programozás, míg nagyobb esetekben metaheurisztikus módszerek alkalmazhatók. A probléma nemcsak elméletileg izgalmas, hanem rendkívül gyakorlati jelentőséggel is bír.