function knapsack(capacity, n, weights, values): max_value = 0 for each subset of items: total_weight = 0 total_value = 0 for each item in subset: total_weight += weights[item] total_value += values[item] if total_weight <= capacity and total_value > max_value: max_value = total_value return max_value
function knapsack(capacity, n, weights, values): max_value = 0 for each subset of items: total_weight = 0 total_value = 0 for each item in subset: total_weight += weights[item] if total_weight > capacity: total_value = 0 break total_value += values[item] if total_value > max_value: max_value = total_value return max_value
intknapsack(int capacity, int n, int weights[], int values[]) { int max_value = 0; for (int i = 0; i < pow2(n); i++) { int total_weight = 0; int total_value = 0;
for (int j = 0; j < n; j++) { if (i & (1 << j)) { total_weight += weights[j]; if (total_weight > capacity) { total_value = 0; break; } total_value += values[j]; } }
function knapsack(capacity, n, weights, values): max_value = 0 function backtrack(i, current_weight, current_value): if current_weight > capacity: return if i == n: if current_value > max_value: max_value = current_value return backtrack(i + 1, current_weight, current_value) backtrack(i + 1, current_weight + weights[i], current_value + values[i]) backtrack(0, 0, 0) return max_value
其中,第10行表示不选择第i件物品,第11行表示选择第i件物品。
用C语言可以实现上述伪代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#define MAX(a, b) ((a) > (b) ? (a) : (b))
intbacktrack(int i, int current_weight, int current_value, int capacity, int n, int weights[], int values[]) { if (current_weight > capacity) { return INT_MIN; } if (i == n) { return current_value; }
int value_without_item = backtrack(i + 1, current_weight, current_value, capacity, n, weights, values); int value_with_item = backtrack(i + 1, current_weight + weights[i], current_value + values[i], capacity, n, weights, values);
intknapsack(int capacity, int n, int weights[], int values[]) { return MAX(backtrack(0, 0, 0, capacity, n, weights, values), 0); }
不过,无论是穷举法还是回溯法,时间复杂度都是O(2n)。对于大规模的问题是不可行的。
贪心法
还有一种符合直觉的想法是,我们可以按照单位重量的价值从大到小的顺序,依次选择物品放入背包。
1 2 3 4 5 6 7 8 9
function knapsack(capacity, n, weights, values): sort items by value per weight in descending order total_weight = 0 total_value = 0 for each item in items: if total_weight + item.weight <= capacity: total_weight += item.weight total_value += item.value return total_value
function knapsack(capacity, n, weights, values): dp = new int[n+1][capacity+1] for i from 1 to n: for j from weights[i] to capacity: dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i]] + values[i]) return dp[n][capacity]
function knapsack(capacity, n, weights, values): dp = new int[capacity+1] for i from 1 to n: for j from capacity to weights[i]: dp[j] = max(dp[j], dp[j-weights[i]] + values[i]) return dp[capacity]
下面是使用C语言实现的代码:
1 2 3 4 5 6 7 8 9 10 11 12
intknapsack(int capacity, int n, int weights[], int values[]) { int dp[capacity + 1]; memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++) { for (int j = capacity; j >= weights[i - 1]; j--) { dp[j] = MAX(dp[j], dp[j - weights[i - 1]] + values[i - 1]); } }
function knapsack(capacity, n, weights, values): dp = new int[sum(values)+1] for i from 1 to sum(values): dp[i] = INT_MAX dp[0] = 0 for i from 1 to n: for j from sum(values) to values[i]: if dp[j-values[i]] != INT_MAX: dp[j] = min(dp[j], dp[j-values[i]] + weights[i]) for i from sum(values) to 0: if dp[i] <= capacity: return i