docs: def knapsack_iterative_int(items, maxweight):
      r"""
      Iterative knapsack method
  
      Math:
          maximize \sum_{i \in T} v_i
          subject to \sum_{i \in T} w_i \leq W
  
      Notes:
          dpmat is the dynamic programming memoization matrix.
          dpmat[i, w] is the total value of the items with weight at most W
          T is idx_subset, the set of indicies in the optimal solution
  
      CommandLine:
          python -m utool.util_alg --exec-knapsack_iterative_int --show
  
      Example:
          >>> # ENABLE_DOCTEST
          >>> from utool.util_alg import *  # NOQA
          >>> weights = [1, 3, 3, 5, 2, 1] * 2
          >>> items = [(w, w, i) for i, w in enumerate(weights)]
          >>> maxweight = 10
          >>> items = [(.8, 700, 0)]
          >>> maxweight = 2000
          >>> print('maxweight = %r' % (maxweight,))
          >>> print('items = %r' % (items,))
          >>> total_value, items_subset = knapsack_iterative_int(items, maxweight)
          >>> total_weight = sum([t[1] for t in items_subset])
          >>> print('total_weight = %r' % (total_weight,))
          >>> print('items_subset = %r' % (items_subset,))
          >>> result =  'total_value = %.2f' % (total_value,)
          >>> print(result)
          total_value = 0.80
  
      Ignore:
          DPMAT = [[dpmat[r][c] for c in range(maxweight)] for r in range(len(items))]
          KMAT  = [[kmat[r][c] for c in range(maxweight)] for r in range(len(items))]
      """
      values  = [t[0] for t in items]
      weights = [t[1] for t in items]
      maxsize = maxweight + 1
      # Sparse representation seems better
      dpmat = defaultdict(lambda: defaultdict(lambda: np.inf))
      kmat = defaultdict(lambda: defaultdict(lambda: False))
      idx_subset = []  # NOQA
      for w in range(maxsize):
          dpmat[0][w] = 0
      # For each item consider to include it or not
      for idx in range(len(items)):
          item_val = values[idx]
          item_weight = weights[idx]
          # consider at each possible bag size
          for w in range(maxsize):
              valid_item = item_weight <= w
              if idx > 0:
                  prev_val = dpmat[idx - 1][w]
                  prev_noitem_val = dpmat[idx - 1][w - item_weight]
              else:
                  prev_val = 0
                  prev_noitem_val = 0
              withitem_val = item_val + prev_noitem_val
              more_valuable = withitem_val > prev_val
              if valid_item and more_valuable:
                  dpmat[idx][w] = withitem_val
                  kmat[idx][w] = True
              else:
                  dpmat[idx][w] = prev_val
                  kmat[idx][w] = False
      # Trace backwards to get the items used in the solution
      K = maxweight
      for idx in reversed(range(len(items))):
          if kmat[idx][K]:
              idx_subset.append(idx)
              K = K - weights[idx]
      idx_subset = sorted(idx_subset)
      items_subset = [items[i] for i in idx_subset]
      total_value = dpmat[len(items) - 1][maxweight]
      return total_value, items_subset