Task: Knapsack problem_Bounded




Go: package main

import "fmt"

type Item struct {
	name               string
	weight, value, qty int
}

var items = []Item{
	{"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},
	{"suntancream",		11,	70,	1},
	{"camera",		32,	30,	1},
	{"T-shirt",		24,	15,	2},
	{"trousers",		48,	10,	2},
	{"umbrella",		73,	40,	1},
	{"w-trousers",		42,	70,	1},
	{"w-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},
}

type Chooser struct {
	Items []Item
	cache map[key]solution
}

type key struct {
	w, p int
}

type solution struct {
	v, w int
	qty  []int
}

func (c Chooser) Choose(limit int) (w, v int, qty []int) {
	c.cache = make(map[key]solution)
	s := c.rchoose(limit, len(c.Items)-1)
	c.cache = nil 
	return s.v, s.w, s.qty
}

func (c Chooser) rchoose(limit, pos int) solution {
	if pos < 0 || limit <= 0 {
		return solution{0, 0, nil}
	}

	key := key{limit, pos}
	if s, ok := c.cache[key]; ok {
		return s
	}

	best_i, best := 0, solution{0, 0, nil}
	for i := 0; i*items[pos].weight <= limit && i <= items[pos].qty; i++ {
		sol := c.rchoose(limit-i*items[pos].weight, pos-1)
		sol.v += i * items[pos].value
		if sol.v > best.v {
			best_i, best = i, sol
		}
	}

	if best_i > 0 {
		
		
		
		old := best.qty
		best.qty = make([]int, len(items))
		copy(best.qty, old)
		best.qty[pos] = best_i
		best.w += best_i * items[pos].weight
	}
	c.cache[key] = best
	return best
}

func main() {
	v, w, s := Chooser{Items: items}.Choose(400)

	fmt.Println("Taking:")
	for i, t := range s {
		if t > 0 {
			fmt.Printf("  %d of %d %s\n", t, items[i].qty, items[i].name)
		}
	}
	fmt.Printf("Value: %d; weight: %d\n", v, w)
}




Python: 

import strformat
import tables


type Item = tuple[name: string; weight, value, pieces: int]


const Items: seq[Item] = @[("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)
                          ]

type

  
  Number = range[0..Items.high]

  
  ExpandedItem = tuple[num: Number; weight, value: int]




proc expandedItems(items: seq[Item]): seq[ExpandedItem] =
  
  for idx, item in Items:
    for _ in 1..item.pieces:
      result.add((idx.Number, item.weight, item.value))

const ItemList = expandedItems(Items)

type

  
  ExpandedIndex = 0..ItemList.high

  
  Choice = tuple[indexes: set[ExpandedIndex]; weight, value: int]


var cache: Table[tuple[index, weight: int], Choice]




proc select(idx, weightLimit: int): Choice =
  

  if idx < 0 or weightLimit == 0:
    return

  if (idx, weightLimit) in cache:
    return cache[(idx, weightLimit)]

  let weight = ItemList[idx].weight
  if weight > weightLimit:
    return select(idx - 1, weightLimit)

  
  result = select(idx - 1, weightLimit)

  
  var result1 = select(idx - 1, weightLimit - weight)
  inc result1.value, ItemList[idx].value

  
  if result1.value > result.value:
    result = (result1.indexes + {idx.ExpandedIndex}, result1.weight + weight, result1.value)

  cache[(idx, weightLimit)] = result



let (indexes, weight, value) = select(ItemList.high, 400)


var pieces = newSeq[int](Items.len)
for idx in indexes:
  inc pieces[ItemList[idx].num]

echo "List of items:"
for num in 0..Items.high:
  if pieces[num] > 0:
    echo fmt"– {pieces[num]} of {Items[num].pieces} {Items[num].name}"
echo ""
echo "Total weight: ", weight
echo "Total value: ", value