繁体   English   中英

使用k个硬币的路径数

[英]Number of paths using k coins

给定一个矩阵,其中每个单元都有一定数量的硬币。 用正好k硬币计算从右上角到右下角的方式数。 我们可以从单元(i, j)移至(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)为使用k硬币从M[0][0]M[i][j]方法数量。

 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],这是有意义的。 在这种情况下,您想要

  • 将[1] [1] [1] = 1初始化为1,1而不是0,0并在上述循环中跳过1,1
  • 现在从k减去M [i-1] [j-1]个硬币,而不是1
  • 如果您确实需要应付10x10,请将MAX_COINS加1,因为否则您只能接受9x9

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM