Trying to understand this Dynamic Programming solution
We are going to build up the matching with a top-bottom approach. Before proceed your intuition is correct. We need two indexes for our solution, that it would be a recursive function $f$ based on a index $i\in [n]$ and index $j\in[m]$. 

This is the definition for $f$.
$$f(i,j):= \text{The optimal* matching between the elements from }\{a_1, a_2, \cdots, a_i \}\text{ with $i$ elements from } \{b_1, b_2, \cdots, b_j\}.$$

The first thing as with other recursive methods, is establish the well-defined bases cases of the recursion. These are the following.
$$
\begin{align}
f(i,1) &amp;= |a_i - b_1|\ \ \ \forall i\in [n]\\
f(1,j) &amp;= \min\ \{\ f(1, j-1),\ |a_1 - b_j|\ \} \ \ \ \forall j\in [m]\\
\end{align}
$$
These are when we have just one element from $B$ and just one element from $A$, respectively. 

Thinking like $f$ is working yet as we expected, we can define it as follows with $i\in [n]$ and $j\in [m]$.

$$
f(i,j) = \min \ \begin{cases}
f(i-1, j-1) + |a_i - b_j| &amp; \text{we match $a_i$ with $b_j$}\\
f(i, j-1)&amp;\text{we won't pair $a_i$ with $b_j$}
\end{cases}.
$$

Be aware in the recursion for the corner cases, these are when $f$ is not defined. They are  when $i$ or $j$, or even both are less than or equal to zero, for these cases, we are gonna say, $f(i,j) = \infty$.

So, what is the answer (?). Because, we are using top-bottom approach and based on the definition of $f$, after compute $f(n, m)$, it should give us the answer. Notice, that this way is one of many methods using dynamic programming, and sincerely, it is almost the same as the solution your provided in the link, but here it is just more explicit. 

Maybe like a pseudocode, we can do this in Python with the following implementation.

@memo
def f(n, m):
    global a, b
    if m &lt;= 0 or n &lt;= 0:
        return float('inf')
    if n == 1:
        return min(f(1, m - 1), abs(a[0] - b[m - 1]))
    if m == 1:
        return abs(a[n-1] - b[0])
    x = f(n - 1, m - 1) + abs(a[n - 1] - b[m - 1])  # take b_m
    y = f(n, m - 1)  # dont take b_m
    return min(x, y)

print f(len(a), len(b))


My @memo decorator is the following, and is the key of a technique that involved dynamic programing, caching o memoization. 
    from functools import wraps
    def memo(func):  # memoization
        cache = {}

    @wraps(func)
    def wrap(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrap