Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Knapsack.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
48# ifndef KNAPSACK_H
49# define KNAPSACK_H
50
51# include <algorithm>
52# include <concepts>
53# include <cstddef>
54# include <limits>
55# include <type_traits>
56# include <utility>
57
58# include <ah-errors.H>
59# include <tpl_array.H>
60
61namespace Aleph
62{
64 template <typename W, typename V>
66 {
69 };
70
71
73 template <typename V>
79
80
81 namespace knapsack_detail
82 {
83 template <std::integral W>
84 [[nodiscard]] inline size_t
85 to_size_checked(const W value, const char *fn_name,
86 const char *field_name)
87 {
88 if constexpr (std::is_signed_v<W>)
89 ah_domain_error_if(value < W{})
90 << fn_name << ": " << field_name << " must be non-negative";
91
92 using UW = std::make_unsigned_t<W>;
93 const UW uvalue = static_cast<UW>(value);
94 if constexpr (sizeof(UW) > sizeof(size_t))
95 ah_out_of_range_error_if(uvalue > static_cast<UW>( std::numeric_limits<size_t>::max()))
96 << fn_name << ": " << field_name << " is too large for size_t";
97
98 return static_cast<size_t>(uvalue);
99 }
100
101 template <std::integral W, typename V>
102 [[nodiscard]] inline Array<size_t>
104 const char *fn_name)
105 {
107 for (size_t i = 0; i < items.size(); ++i)
108 weights(i) = to_size_checked(items[i].weight, fn_name, "item weight");
109 return weights;
110 }
111 } // namespace knapsack_detail
112
113
129 template <typename V, std::integral W>
131 knapsack_01(const Array<Knapsack_Item<W, V>> & items, W capacity)
132 {
133 const size_t n = items.size();
134 const size_t C
135 = knapsack_detail::to_size_checked(capacity, "knapsack_01", "capacity");
137 = knapsack_detail::extract_weights_checked(items, "knapsack_01");
138
139 if (n == 0)
141
142 // dp[i][w] = best value using items 0..i-1 with capacity w
143 Array<Array<V>> dp;
144 dp.reserve(n + 1);
145 for (size_t i = 0; i <= n; ++i)
146 {
147 Array<V> row = Array<V>::create(C + 1);
148 for (size_t w = 0; w <= C; ++w)
149 row(w) = V{};
150 dp.append(std::move(row));
151 }
152
153 for (size_t i = 1; i <= n; ++i)
154 {
155 const size_t wi = weights[i - 1];
156 const V vi = items[i - 1].value;
157 for (size_t w = 0; w <= C; ++w)
158 if (wi <= w and dp[i - 1][w - wi] + vi > dp[i - 1][w])
159 dp[i][w] = dp[i - 1][w - wi] + vi;
160 else
161 dp[i][w] = dp[i - 1][w];
162 }
163
164 // reconstruct
166 size_t w = C;
167 for (size_t i = n; i > 0; --i)
168 if (dp[i][w] != dp[i - 1][w])
169 {
170 sel.append(i - 1);
171 w -= weights[i - 1];
172 }
173
174 // reverse to ascending order
175 Array<size_t> selected;
176 selected.reserve(sel.size());
177 for (size_t k = sel.size(); k > 0; --k)
178 selected.append(sel[k - 1]);
179
180 return Knapsack_Result<V>{dp[n][C], std::move(selected)};
181 }
182
183
197 template <typename V, std::integral W>
198 [[nodiscard]] V
199 knapsack_01_value(const Array<Knapsack_Item<W, V>> & items, W capacity)
200 {
201 const size_t n = items.size();
202 const size_t C = knapsack_detail::to_size_checked(
203 capacity, "knapsack_01_value", "capacity");
205 items, "knapsack_01_value");
206
207 if (n == 0)
208 return V{};
209
210 Array<V> dp = Array<V>::create(C + 1);
211 for (size_t w = 0; w <= C; ++w)
212 dp(w) = V{};
213
214 for (size_t i = 0; i < n; ++i)
215 {
216 const size_t wi = weights[i];
217 const V vi = items[i].value;
218 for (size_t w = C; w >= wi and w != static_cast<size_t>(-1); --w)
219 if (dp[w - wi] + vi > dp[w])
220 dp(w) = dp[w - wi] + vi;
221 }
222
223 return dp[C];
224 }
225
226
245 template <typename V, std::integral W>
247 knapsack_unbounded(const Array<Knapsack_Item<W, V>> & items, W capacity)
248 {
249 const size_t n = items.size();
250 const size_t C = knapsack_detail::to_size_checked(
251 capacity, "knapsack_unbounded", "capacity");
253 items, "knapsack_unbounded");
254
255 if (n == 0)
257
258 for (size_t i = 0; i < n; ++i)
259 if (weights[i] == 0 and items[i].value > V{})
261 << "knapsack_unbounded: zero-weight item with positive value "
262 << "leads to unbounded optimum";
263
264 Array<V> dp = Array<V>::create(C + 1);
265 // choice[w] = which item was last added at capacity w
267 constexpr size_t NONE = std::numeric_limits<size_t>::max();
268 for (size_t w = 0; w <= C; ++w)
269 {
270 dp(w) = V{};
271 choice(w) = NONE;
272 }
273
274 for (size_t w = 1; w <= C; ++w)
275 for (size_t i = 0; i < n; ++i)
276 if (const size_t wi = weights[i]; wi <= w and dp[w - wi] + items[i].value > dp[w])
277 {
278 dp(w) = dp[w - wi] + items[i].value;
279 choice(w) = i;
280 }
281
282 // reconstruct
284 size_t w = C;
285 while (w > 0 and choice[w] != NONE)
286 {
287 const size_t idx = choice[w];
288 sel.append(idx);
289 w -= weights[idx];
290 }
291
292 return Knapsack_Result<V>{dp[C], std::move(sel)};
293 }
294
295
315 template <typename V, std::integral W>
318 const Array<size_t> & counts, W capacity)
319 {
320 ah_invalid_argument_if(items.size() != counts.size())
321 << "knapsack_bounded: items and counts must have same size";
322
323 const size_t n = items.size();
324 const size_t C = knapsack_detail::to_size_checked(
325 capacity, "knapsack_bounded", "capacity");
327 items, "knapsack_bounded");
328
329 if (n == 0)
331
332 // Binary decomposition: for item i with count c, create groups
333 // of 1, 2, 4, ..., 2^k, remainder
335 Array<size_t> origin; // maps expanded index -> original index
336 Array<size_t> multiplier; // how many copies this group represents
337
338 for (size_t i = 0; i < n; ++i)
339 {
340 const size_t wi = weights[i];
341 size_t rem = counts[i];
342 size_t k = 1;
343 while (rem > 0)
344 {
345 const size_t take = std::min(k, rem);
346
347 if (wi == 0 or take <= C / wi)
348 {
350 static_cast<W>(wi * take),
351 static_cast<V>(take) * items[i].value
352 });
353 origin.append(i);
354 multiplier.append(take);
355 }
356
357 rem -= take;
358 if (rem == 0)
359 break;
360
361 if (k > std::numeric_limits<size_t>::max() / 2)
362 k = rem;
363 else
364 k *= 2;
365 }
366 }
367
368 // Solve as 0/1
369 auto result = knapsack_01(expanded, capacity);
370
371 // Map back to original indices
373 for (size_t k = 0; k < result.selected_items.size(); ++k)
374 {
375 const size_t ei = result.selected_items[k];
376 const size_t orig = origin[ei];
377 const size_t mult = multiplier[ei];
378 for (size_t j = 0; j < mult; ++j)
379 sel.append(orig);
380 }
381
382 return Knapsack_Result<V>{result.optimal_value, std::move(sel)};
383 }
384} // namespace Aleph
385
386# endif // KNAPSACK_H
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:579
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:639
long double w
Definition btreepic.C:153
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:194
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:315
Array< size_t > extract_weights_checked(const Array< Knapsack_Item< W, V > > &items, const char *fn_name)
Definition Knapsack.H:103
size_t to_size_checked(const W value, const char *fn_name, const char *field_name)
Definition Knapsack.H:85
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
V knapsack_01_value(const Array< Knapsack_Item< W, V > > &items, W capacity)
0/1 Knapsack — value only (space-optimized).
Definition Knapsack.H:199
Knapsack_Result< V > knapsack_01(const Array< Knapsack_Item< W, V > > &items, W capacity)
0/1 Knapsack with item reconstruction.
Definition Knapsack.H:131
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Knapsack_Result< V > knapsack_bounded(const Array< Knapsack_Item< W, V > > &items, const Array< size_t > &counts, W capacity)
Bounded Knapsack with reconstruction.
Definition Knapsack.H:317
Knapsack_Result< V > knapsack_unbounded(const Array< Knapsack_Item< W, V > > &items, W capacity)
Unbounded Knapsack with reconstruction.
Definition Knapsack.H:247
An item for knapsack problems.
Definition Knapsack.H:66
V value
Value (or profit) of the item.
Definition Knapsack.H:68
W weight
Weight (or cost) of the item.
Definition Knapsack.H:67
Result of a knapsack computation.
Definition Knapsack.H:75
Array< size_t > selected_items
Indices (0-based) of selected items.
Definition Knapsack.H:77
V optimal_value
Optimal objective value.
Definition Knapsack.H:76
size_t V
static int * k
Dynamic array container with automatic resizing.