The dynamic programming algoritm uses a memoized recursive function that solves a more flexible subproblem :
The function takes a number k of rows to fill, and for each column, the number of 1s it has to place in those k rows.
It has to return the number of possible assignments of 1s in the block of k rows such that each row contains n/2 1s, and each column contains the proper number of 1s stated in the argument.
The principle is that :
if a column has to contain a negative number of 1s, there is 0 solution.
if k=0 (and all the columns have to be empty), then there is 1 solution.
otherwise, an assignment of a block of k rows is an assignment of the 1st row + an assignment of a block (k-1) rows.
So it iterates over the possible assignments of the 1st row. For each candidate assignment, it recursively asks itself for the number of ways of completing the remaining (k-1) rows with the updated information about the number of 1s that have to be in each column.
If you don't memoise the function, it is exactly what the backtracking algorithm does, essentially it is n nested extremely big loops.
If you memoise the function, you will find that it is called for the same k and for the same constraints on the column a great number of times.
For example, while doing the backtracking algorithm, at some point you chose the assignment A1 for row 1 and A2 for row 2, and proceed to count every solution starting with (A1,A2) with (n-2) nested loops. Then later in the execution, you choose the assignment A2 for row 1 and A1 for row 2, and proceed to count every solution starting with (A2,A1), again with (n-2) nested loops.
But if you look carefully at the subproblem you have to solve, it has the same constraints in both case.
A solution in the first case is the same as a solution in the 2nd case, only with the first two rows switched. So you are counting the same number twice.
If you memoize your recursive function, then it will recognize that these two subproblems are equivalent because they ask for the same constraints, and only compute its result once. In all the later calls it will directly return with that same result, and avoid a very expensive recomputation.