Data update

This commit is contained in:
Ingy döt Net 2025-08-11 18:05:26 -07:00
parent 4d5544505c
commit 4924dd0264
3073 changed files with 55820 additions and 4408 deletions

View file

@ -0,0 +1,143 @@
with Ada.Text_IO;
procedure Knapsack_Bounded is
subtype Item_Name is String (1 .. 22);
type Item_Weight is new Natural;
type Item_Value is new Natural;
type Item_Count is new Natural;
type Item_Pool is record
Name : Item_Name;
Weight : Item_Weight;
Value : Item_Value;
Count : Item_Count;
end record;
type Item_Bag is array (1 .. 22) of Item_Pool;
Candidates : constant Item_Bag :=
(
("map ", 9, 150, 1),
("compass ", 13, 35, 1),
("water ", 153, 200, 2),
("sandwich ", 50, 60, 2),
("glucose ", 15, 60, 2),
("tin ", 68, 45, 3),
("banana ", 27, 60, 3),
("apple ", 39, 40, 3),
("cheese ", 23, 30, 1),
("beer ", 52, 10, 3),
("suntan cream ", 11, 70, 1),
("camera ", 32, 30, 1),
("T-shirt ", 24, 15, 2),
("trousers ", 48, 10, 2),
("umbrella ", 73, 40, 1),
("waterproof trousers ", 42, 70, 1),
("waterproof overclothes", 43, 75, 1),
("note-case ", 22, 80, 1),
("sunglasses ", 7, 20, 1),
("towel ", 18, 12, 2),
("socks ", 4, 50, 1),
("book ", 30, 10, 2)
);
Capacity : constant Item_Weight := 400;
Answer : Item_Bag;
type Item_Table is
array (Item_Bag'First - 1 .. Item_Bag'Last,
Item_Weight'First .. Capacity) of Item_Value;
Working_Table : Item_Table := (others => (others => 0));
procedure Fill_Table is
Item : Item_Pool;
V, Max_Value : Item_Value;
W : Item_Weight;
begin
for I in Candidates'Range loop
Item := Candidates (I);
for J in Working_Table'Range (2) loop
Max_Value := Working_Table (I - 1, J);
for K in 1 .. Item.Count loop
V := Item_Value (K) * Item.Value;
W := Item_Weight (K) * Item.Weight;
if W <= J then
Max_Value := Item_Value'Max
(Max_Value, Working_Table (I - 1, J - W) + V);
end if;
end loop;
Working_Table (I, J) := Max_Value;
end loop;
end loop;
end Fill_Table;
procedure Trace_Answer is
Cap : Item_Weight := Capacity;
Count : Item_Count;
W, Weight : Item_Weight;
V, Max_Value : Item_Value;
begin
for I in reverse Answer'Range loop
Answer (I) := Candidates (I);
Max_Value := Working_Table (I, Cap);
Count := 0;
Weight := 0;
for J in 1 .. Candidates (I).Count loop
W := Item_Weight (J) * Answer (I).Weight;
V := Item_Value (J) * Answer (I).Value;
if W <= Cap and then
Max_Value = Working_Table (I - 1, Cap - W) + V then
Weight := W;
Count := J;
end if;
end loop;
Cap := Cap - Weight;
Answer (I).Count := Count;
end loop;
end Trace_Answer;
procedure Show_Answer is
package Count_IO is new Ada.Text_IO.Integer_IO (Item_Count);
package Weight_IO is new Ada.Text_IO.Integer_IO (Item_Weight);
package Value_IO is new Ada.Text_IO.Integer_IO (Item_Value);
Item : Item_Pool;
C, Total_Items : Item_Count := 0;
W, Total_Weight : Item_Weight := 0;
V, Total_Value : Item_Value := 0;
Totals : String (Item_Name'Range) := "Totals ";
begin
for I in Answer'Range loop
Item := Answer (I);
C := Item.Count;
W := Item.Weight * Item_Weight (Item.Count);
V := Item.Value * Item_Value (Item.Count);
Total_Items := Total_Items + Item.Count;
Total_Weight := Total_Weight + W;
Total_Value := Total_Value + V;
if C > 0 then
Ada.Text_IO.Put (Item.Name);
Count_IO.Put (C);
Weight_IO.Put (W);
Value_IO.Put (V);
Ada.Text_IO.New_Line;
end if;
end loop;
Ada.Text_IO.Put (Totals);
Count_IO.Put (Total_Items);
Weight_IO.Put (Total_Weight);
Value_IO.Put (Total_Value);
Ada.Text_IO.New_Line;
end Show_Answer;
begin
Fill_Table;
Trace_Answer;
Show_Answer;
end Knapsack_Bounded;

View file

@ -0,0 +1,184 @@
module knapsack_mod
implicit none
!--------------------------------------------------------------------
! Define an item type with a name, weight, value, and available count.
!--------------------------------------------------------------------
type :: item
character(len=24) :: name ! Name (for display purposes)
integer :: weight ! Weight of one copy of the item
integer :: value ! Value of one copy of the item
integer :: count ! Maximum number of copies available
end type item
!--------------------------------------------------------------------
! Define a parameter array of items.
!--------------------------------------------------------------------
type(item), parameter :: items(*) = [ &
item("map ", 9, 150, 1), &
item("compass ", 13, 35, 1), &
item("water ", 153, 200, 2), &
item("sandwich ", 50, 60, 2), &
item("glucose ", 15, 60, 2), &
item("tin ", 68, 45, 3), &
item("banana ", 27, 60, 3), &
item("apple ", 39, 40, 3), &
item("cheese ", 23, 30, 1), &
item("beer ", 52, 10, 3), &
item("suntan cream ", 11, 70, 1), &
item("camera ", 32, 30, 1), &
item("T-shirt ", 24, 15, 2), &
item("trousers ", 48, 10, 2), &
item("umbrella ", 73, 40, 1), &
item("waterproof trousers ", 42, 70, 1), &
item("waterproof overclothes ", 43, 75, 1), &
item("note-case ", 22, 80, 1), &
item("sunglasses ", 7, 20, 1), &
item("towel ", 18, 12, 2), &
item("socks ", 4, 50, 1), &
item("book ", 30, 10, 2) &
]
contains
!--------------------------------------------------------------------
! Function: knapsack
!
! Description:
! Solves the bounded knapsack problem using dynamic programming.
! This version retains a two-dimensional DP table (m) and applies
! binary splitting to efficiently handle items available in multiple
! copies.
!
! Input:
! w - Maximum weight capacity of the knapsack.
!
! Output:
! s - An integer array (of size equal to the number of items)
! where s(i) indicates how many copies of item i are selected
! in the optimal solution.
!--------------------------------------------------------------------
function knapsack(w) result(s)
integer, intent(in) :: w ! Knapsack capacity
integer, allocatable :: s(:) ! Solution vector of item counts
integer, allocatable :: m(:,:) ! DP table: m(i,j) is the maximum value using items 1..i with capacity j
integer :: n ! Total number of items
integer :: i, j, v, k ! Loop indices and temporary value
! Variables for binary splitting of the count of an item.
integer :: available ! Remaining copies to process for the current item
integer :: r ! Current binary splitting factor
integer :: k_group ! Number of copies in the current group
integer :: group_weight ! Total weight of the current group (k_group * item weight)
integer :: group_value ! Total value of the current group (k_group * item value)
! Determine the number of items available.
n = size(items)
! Allocate the solution vector and DP table.
! DP table m is sized from row 0 (base case: no items) to n, and column 0 to w.
allocate(s(n), m(0:n, 0:w))
! Initialize both the DP table and the solution vector to 0.
m = 0
s = 0
!-------------------------------
! DP Table Construction
!-------------------------------
! For each item i (from 1 to n), determine the best value achievable
! with a knapsack capacity from 0 to w.
do i = 1, n
! First, copy the previous row into the current row.
! This means if we do not take any of item i, the value remains as before.
do j = 0, w
m(i, j) = m(i-1, j)
end do
! Process item i using binary splitting:
! Instead of iterating k from 1 to items(i)%count one by one, we split
! the available copies into groups for an efficient "0/1 item" update.
available = items(i)%count
r = 1
do while (available > 0)
! Use k_group copies, which is the minimum of the current binary factor and available copies.
k_group = min(r, available)
! Compute group weight and value for k_group copies.
group_weight = k_group * items(i)%weight
group_value = k_group * items(i)%value
! Perform a 0/1 knapsack update for this group.
! Loop backwards from capacity w down to group_weight so that each group
! is only used once. We update row i (which already contains m(i-1, :) as baseline).
do j = w, group_weight, -1
! If adding this group improves the total value, update m(i,j).
v = m(i, j - group_weight) + group_value
if (v > m(i, j)) then
m(i, j) = v
end if
end do
! Subtract the number of copies processed and double the binary factor.
available = available - k_group
r = r * 2
end do
end do
!-------------------------------
! Backtracking to Retrieve the Solution
!-------------------------------
! Starting from the maximum capacity and the last item, deduce how many copies
! of each item were used in the optimal solution.
j = w
do i = n, 1, -1
! Store the optimal value for items 1..i with current capacity j.
v = m(i, j)
! For item i, try every possible count from 0 to items(i)%count.
do k = 0, items(i)%count
if (j >= k * items(i)%weight) then
! Check if the current value resulted from taking k copies of item i.
if (v == m(i-1, j - k*items(i)%weight) + k*items(i)%value) then
s(i) = k ! Record k copies for item i
j = j - k*items(i)%weight ! Decrease the remaining capacity
exit ! Proceed to the next (previous) item
end if
end if
end do
end do
end function knapsack
end module knapsack_mod
program main
use knapsack_mod
implicit none
integer, allocatable :: s(:)
integer :: i, total_count, total_weight, total_value
s = knapsack(400)
total_count = 0
total_weight = 0
total_value = 0
write(*,'(A22 A6 A7 A6)') 'Item', 'Count', 'Weight', 'Value'
write(*,'("------------------------------------------------")')
do i = 1, size(items)
if (s(i) > 0) then
write(*,'(A22 I5 I6 I6)') &
items(i)%name, s(i), s(i)*items(i)%weight, s(i)*items(i)%value
total_count = total_count + s(i)
total_weight = total_weight + s(i)*items(i)%weight
total_value = total_value + s(i)*items(i)%value
end if
end do
write(*,'("------------------------------------------------")')
write(*,'(A22 I5 I6 I6)') 'Totals:', total_count, total_weight, total_value
end program main

View file

@ -0,0 +1,180 @@
#!/usr/bin/env lua
--- knapsack packing for max value under wieght limit
-- A: use value/weight score as pre-sort
-- B: initial run with no items excluded
-- C: try combos excluding each item for best value
--- table of tables
-- {name weight value quantity wt/val }
items = {
{"map", 9, 150, 1},
{"compass", 13, 35, 1},
{"water", 153, 200, 2},
{"sandwich", 50, 60, 2},
{"glucose", 15, 60, 2},
{"tin", 68, 45, 3},
{"banana", 27, 60, 3},
{"apple", 39, 40, 3},
{"cheese", 23, 30, 1},
{"beer", 52, 10, 3},
{"suntan cream", 11, 70, 1},
{"camera", 32, 30, 1},
{"t-shirt", 24, 15, 2},
{"trousers", 48, 10, 2},
{"umbrella", 73, 40, 1},
{"waterproof trousers", 42, 70, 1},
{"waterproof overclothes", 43, 75, 1},
{"note-case", 22, 80, 1},
{"sunglasses", 7, 20, 1},
{"towel", 18, 12, 2},
{"socks", 4, 50, 1},
{"book", 30, 10, 2},
}
-- for output
function print_as_sack(its)
if its == nil then return end
-- format columns
-- [20 |8 |8 |8 ]
local head_fmt = "%-20s\t%-8s\t%-8s\t%-8s"
local data_fmt = "%-20s\t%-8d\t%-8d\t%-8d"
local head_table =
string.format(head_fmt, "item", "weight", "value", "quantity")
io.write(head_table, "\n")
line = string.rep("-" , 64)
io.write(line, "\n")
for n=1,#its do
it = its[n]
local name,wt,val,q = table.unpack(it)
local fmt_table =
string.format(data_fmt, name, wt, val, q)
io.write(fmt_table, "\n")
end
io.write(line, "\n")
end
-- calc value:weight ratio
function append_wv (its)
for index, it in pairs(its) do
local name,wt,val,q = table.unpack(it)
wv = val / wt
it[#it+1] = wv -- append
end
end
-- sort by 5th item of each table entry
function sort_by_wv (its)
-- sorts decreasing
local wv_sorter = function(a,b) return a[5] > b[5] end
table.sort(its, wv_sorter)
end
-- pack sorted by v:w ratio
-- all or none per item
function add_up (its, max, excl)
local sack_items = {}
local sack = {}
local this_weight = 0
local this_value = 0
for i = 1,#its do
it = its[i]
-- is same table?
-- lua has no continue keyword
if it == excl then goto continue end
-- unpack into vars
local name,wt,val,q,wv = table.unpack(it)
local count = 0
local w = 0
for j = 1, q do
local t_wt = wt +this_weight
if t_wt < max then
this_value = this_value + val
this_weight = t_wt
count = count + 1
end
end
if this_weight >= max then break end
if count > 0 then
_s = {name, count}
table.insert (sack, _s)
end
::continue:: --skip item, continue
end -- for items
-- go through chosen sack
-- make sack of items
for s = 1,#sack do
local s_item = sack[s]
local s_name,s_count = table.unpack(s_item)
for j = 1,#its do
local it = its[j]
local iname = it[1]
if iname == s_name then
it[4] = s_count
table.insert(sack_items, it)
end -- if
end -- for j
end -- for sack
-- update best
if this_value > best_value then
best_value = this_value
best_weight = this_weight
best_sack = sack_items
end
end -- function add_up
-- Main execution
if debug.getinfo(1).what == "main" then
max_weight = 400
best_weight = 0
best_value = 0
best_sack = {}
start = os.clock()
append_wv(items) -- add weight/value
sort_by_wv(items) -- sort by wv
add_up(items, max_weight, {}) -- first try
-- with each item excluded
for i = 1, #items do
add_up(items, max_weight, items[i])
end
stop = os.clock()
time = stop - start -- seconds
usec_time = time * 1e6 --microseconds
-- output
print_as_sack(best_sack)
print ("value:\t", best_value)
print("weight:\t", best_weight)
print("time:\t" , usec_time , " usec")
os.exit(0)
end
-- end

View file

@ -0,0 +1,99 @@
use std::collections::HashMap;
fn main() {
let max_wt = 400;
let grouped_items = vec![
("map", 9, 150, 1),
("compass", 13, 35, 1),
("water", 153, 200, 3),
("sandwich", 50, 60, 2),
("glucose", 15, 60, 2),
("tin", 68, 45, 3),
("banana", 27, 60, 3),
("apple", 39, 40, 3),
("cheese", 23, 30, 1),
("beer", 52, 10, 3),
("suntan cream", 11, 70, 1),
("camera", 32, 30, 1),
("t-shirt", 24, 15, 2),
("trousers", 48, 10, 2),
("umbrella", 73, 40, 1),
("waterproof trousers", 42, 70, 1),
("waterproof overclothes", 43, 75, 1),
("note-case", 22, 80, 1),
("sunglasses", 7, 20, 1),
("towel", 18, 12, 2),
("socks", 4, 50, 1),
("book", 30, 10, 2),
];
let mut items = Vec::new();
for &(item, wt, val, n) in &grouped_items {
for _ in 0..n {
items.push((item, wt, val));
}
}
let bagged = knapsack01_dp(&items, max_wt);
// Count and group the bagged items
let mut counts: HashMap<&str, i32> = HashMap::new();
for &(item, _, _) in &bagged {
*counts.entry(item).or_insert(0) += 1;
}
// Sort and print the results
let mut sorted_counts: Vec<_> = counts.iter().collect();
sorted_counts.sort_by_key(|&(item, _)| *item);
println!("Bagged the following {} items", bagged.len());
for (item, count) in sorted_counts {
println!(" {} off: {}", count, item);
}
let total_value: i32 = bagged.iter().map(|&(_, _, val)| val).sum();
let total_weight: i32 = bagged.iter().map(|&(_, wt, _)| wt).sum();
println!("for a total value of {} and a total weight of {}",
total_value, total_weight);
}
fn knapsack01_dp<'a>(items: &'a [(&'a str, i32, i32)], limit: i32) -> Vec<(&'a str, i32, i32)> {
let n = items.len();
let limit_usize = limit as usize;
// Create DP table
let mut table = vec![vec![0; (limit_usize + 1) as usize]; n + 1];
for j in 1..=n {
let (_, wt, val) = items[j-1];
let wt_usize = wt as usize;
for w in 1..=limit_usize {
if wt_usize > w {
table[j][w] = table[j-1][w];
} else {
table[j][w] = std::cmp::max(
table[j-1][w],
table[j-1][w - wt_usize] + val
);
}
}
}
// Backtrack to find items
let mut result = Vec::new();
let mut w = limit_usize;
for j in (1..=n).rev() {
let was_added = table[j][w] != table[j-1][w];
if was_added {
result.push(items[j-1]);
w -= items[j-1].1 as usize;
}
}
result
}