imsuck12's blog

By imsuck12, 12 months ago, In English

Inspired by nor's blog (with permission). See comparison at the end of the post. And check his blog out. There's some interesting stuff on it :D

Disclaimer: You need C++17 for this to compile.

Introduction

When writing recursive DP, one usually need to save the result of a call (memoization) to prevent excessive computation. In python it's as easy as using a decorator:

from functools import cache
@cache
def fibo(n):
    return n if n <= 1 else fibo(n - 1) + fibo(n - 2)

In C++ you'd typically declare a multi-dimensional array, populate it with an unused constant, check if [x][y][z] has been calculated and finally store the result for later use. So much boilerplate... What if you could just paste a code snippet (from code editor or a file) and start solving the problem instead?

DP cache

Full snippet

Let's skip over the implementation details and talk about the interface and how to use it. All you should care about is:

use_cache<R, N>(array<int, N> ds, F f);

Where:

  • R is the type of the DP state.
  • N is how many dimensions you need to use.
  • ds specifies the size of each dimension in the internal N-D array.
  • f is a lambda with a function signature similar to (auto &self, int, char, bool, ...) -> R.

Example usage

Here's the code to count how many integers in the range $$$[1; n]$$$ have the sum of their digits divisible by $$$k$$$:

Code

Notes

I said not to talk about implementation but if you're curious

Difference from nor's implementation

Uses a std::vector internally rather than a __gnu_pbds::gp_hash_table so:

  • Around 2-4 times faster.
  • Less flexible, only works with integers in parameters, whereas with a hash table you can have arrays, vectors, tuples, etc.

Shh I know it's common to find a problem needing top down DP. It is just that this is something interesting to try and implement.

Full text and comments »

  • Vote: I like it
  • +3
  • Vote: I do not like it