Given a matrix where every cell has some number of coins. Count number of ways to reach bottom right from top left with exactly
k
coins. We can move to(i+1, j)
and(i, j+1)
from a cell(i, j)
.Example:
Input: k = 12
mat[][] = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };
Output: 2 There are two paths with 12 coins
1 -> 2 -> 6 -> 2 -> 1
1 -> 2 -> 3 -> 5 -> 1
I created a recursive definition for this:
Let
Count(i, j, k)
be the number of ways to get fromM[0][0]
toM[i][j]
usingk
coins.Count(i, j, k) = { 0: if M[i][j] > k, Count(i-1, j, k-1) + Count(i, j-1, k-1): if M[i][j] < k }
My reasoning for this definition is if the entry in the matrix (the number of coins) is greater than the number of coins we want (k
), then we can't take that path, so the value in the table should be 0.
If the entry is less than or equal to the number of coins, then we can take that path by adding the number of paths from the top (i-1,j)
and left (i, j-1)
. I subtract k
by 1 because the number of coins from the last entry was 1 less.
This is how I do it in the following dynamic programming function:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define MAX_SIZE 10
#define MAX_COINS 20
int Count[MAX_SIZE][MAX_SIZE][MAX_COINS]; // number of ways to get from M[0][0] to M[i][j] using k coins
std::vector<std::vector<int>> M;
int NumOfPaths(int C) {
size_t N = M.size();
// Number of paths to (0,0) with 1 coin is 1
Count[0][0][1] = 1;
// zero coins doesn't work
for (size_t i = 0; i < N; ++i) for (size_t j = 0; j < N; ++j)
Count[i][j][0] = 0;
// If the number of coins is greater than the max then Count[i][j][k] = 0;
// Otherwise Count[i][j][k] = Count[i-1][j][k-1]+Count[i][j-1][k-1]
for (size_t i = 1; i <= N; ++i) {
for (size_t j = 1; j <= N; ++j) {
for (int k = 1; k <= C; ++k) {
if (M[i-1][j-1] > k) Count[i][j][k] = 0;
if (M[i-1][j-1] <= k) Count[i][j][k] = Count[i-1][j][k-1] + Count[i][j-1][k-1];
}
}
}
return Count[N][N][C];
}
int main() {
M = { {1, 2, 3},
{4, 6, 5},
{3, 2, 1}
};
cout << NumOfPaths(12);
}
When I apply the function to the example given in the problem statement, it returns 0, which is incorrect.
I'd like to know where my reasoning went wrong and how I can fix it.
Your problems are
Count[0][0][1] = 1
when it should be Count[0][0][M[0][0]]
(although that's the same here)Count[0][j]
or Count[i][0]
, i.e. there's no complete path to 0,0 from any cell that you're looping over< N
in the loop and to return N-1 as the vector is zero-indexedM[i-1][j-1]
in your loop not M[i][j]
M[i][j]
coins (as Edward and vu1p3n0x point out in the comments)Here's a fixed loop:
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < N; ++j) {
if ((i == 0) && (j == 0)) {
// Skip 0,0: we've populated that already
continue;
}
for (int k = 1; k <= C; ++k) {
if (M[i][j] > k) Count[i][j][k] = 0;
if (M[i][j] <= k) {
int ways = 0;
if (i >= 1) ways += Count[i - 1][j][k - M[i][j]];
if (j >= 1) ways += Count[i][j - 1][k - M[i][j]];
Count[i][j][k] = ways;
}
}
}
}
return Count[N-1][N-1][C];
Alternatively, maybe I misunderstood: were you deliberately counting the top-left square as 1,1 so that you didn't need to check if we were in-bounds for you i-1 and j-1 check, since there'd always be a row of zeroes to spill into? That would make sense for the return [N][N] and the M[i-1][j-1] I suppose. In that case you'd want to