给定一个矩阵,其中每个单元格都有一定数量的硬币。计算用
枚硬币从左上角到达右下角的方法数。我们可以从单元格k
移动到(i+1, j)
和(i, j+1)
。(i, j)
示例:
输入:k = 12
mat[][] = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };
输出: 2 有两条路有12个金币
1 -> 2 -> 6 -> 2 -> 1
1 -> 2 -> 3 -> 5 -> 1
我为此创建了一个递归定义:
令
为使用Count(i, j, k)
硬币从M[0][0]
到M[i][j]
的方式数量。k
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 }
我对这个定义的推理是,如果矩阵中的条目(硬币数量)大于我们想要的硬币数量(
k
),那么我们就不能走这条路,所以表中的值应该是 0.
如果条目小于或等于硬币数量,那么我们可以通过添加从顶部
(i-1,j)
到左侧(i, j-1)
的路径数来选择该路径。我将 k
减 1,因为上次输入的硬币数量少了 1。
这就是我在以下动态规划函数中的做法:
#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);
}
当我将该函数应用于问题陈述中给出的示例时,它返回 0,这是不正确的。
我想知道我的推理哪里出了问题以及如何解决它。
你的问题是
Count[0][0][1] = 1
,而它应该是Count[0][0][M[0][0]]
(尽管这里是一样的)Count[0][j]
或 Count[i][0]
,即,从您循环的任何单元格到 0,0 都没有完整的路径< N
在循环中并返回 N-1 因为向量是零索引的M[i-1][j-1]
测试 k,而不是 M[i][j]
M[i][j]
硬币(正如Edward和vu1p3n0x在评论中指出的那样)这是一个固定循环:
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];
或者,也许我误解了:你是否故意将左上角的正方形计算为 1,1,这样你就不需要检查我们是否在你的 i-1 和 j-1 检查中,因为有总是会出现一排零?我认为这对于返回 [N][N] 和 M[i-1][j-1] 是有意义的。在这种情况下,你会想要
有没有办法在不使用 3d 数组的情况下解决这个问题? “导入java.util.Arrays;
公共类 Number_of_paths_in_a_matrix_with_k_coins {
public static long MOD = 1000000007;
public long numberOfPath(int n, int k, int [][]arr) {
// code here
long dp[][] = new long[n][n];
for (long rows[] : dp){
Arrays.fill(rows,-1);
}
return MemoUtil(k,n-1,n-1,arr,dp);
}
public static long MemoUtil(int k, int i, int j,int arr[][], long dp[][]){
if(i == 0 && j == 0 ) return k == arr[0][0] ? 1 : 0L;
if (i < 0 || j < 0 || k < 0) return 0;
if (dp[i][j] != -1) return dp[i][j];
long left = i > 0 && k > 0 ? MemoUtil(k - arr[i][j], i -1, j, arr,dp) %MOD : 0L;
long right = j > 0 && k > 0 ? MemoUtil(k- arr[i][j], i, j-1, arr, dp) % MOD : 0L;
return dp[i][j] = (left + right) %MOD;
}
} “我尝试过,但这是错误的