Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 动态规划与矩阵的使用_Algorithm_Dynamic - Fatal编程技术网

Algorithm 动态规划与矩阵的使用

Algorithm 动态规划与矩阵的使用,algorithm,dynamic,Algorithm,Dynamic,我总是对动态规划如何使用矩阵来解决问题感到困惑。我大致了解到,矩阵用于存储以前子问题的结果,以便在以后计算更大的问题时使用 但是,如何确定矩阵的维数,我们如何知道矩阵的每一行/每一列应该代表什么值?也就是说,是否有一个构建矩阵的通用过程 例如,如果我们有兴趣使用价值为c1、c2、.cn的硬币来更改货币的数量,那么矩阵的维数应该是多少,每列/每行应该代表什么 任何方向指引都会有所帮助。谢谢大家! DP解决方案使用的数组几乎总是基于问题状态空间的维度,即每个参数的有效值 比如说 fib[i+2] =

我总是对动态规划如何使用矩阵来解决问题感到困惑。我大致了解到,矩阵用于存储以前子问题的结果,以便在以后计算更大的问题时使用

但是,如何确定矩阵的维数,我们如何知道矩阵的每一行/每一列应该代表什么值?也就是说,是否有一个构建矩阵的通用过程

例如,如果我们有兴趣使用价值为c1、c2、.cn的硬币来更改货币的数量,那么矩阵的维数应该是多少,每列/每行应该代表什么


任何方向指引都会有所帮助。谢谢大家!

DP解决方案使用的数组几乎总是基于问题状态空间的维度,即每个参数的有效值

比如说

fib[i+2] = fib[i+1] + fib[i]

def fib(i):
    return fib(i-1)+fib(i-2]
通过在递归函数中实现记忆,可以使这一点更加明显

def fib(i): 
    if( memo[i] == null ) 
         memo[i] = fib(i-1)+fib(i-2)
    return memo[i]

如果递归函数有K个参数,则可能需要K维矩阵。

本章对此进行了很好的解释:
在第178页,它给出了一些方法来识别允许您应用动态规划的子问题。

当一个问题同时表现出两个方面时,它就符合动态规划的条件

其次,动态规划有两种变体:

  • 制表法还是自下而上法
  • 记忆或自上而下的方法(不是记忆!)
动态规划源于这样一种思想,即大问题可以进一步分解为子问题。自下而上的版本只是首先解决这些子问题,然后逐步建立目标解决方案。自顶向下的方法依赖于使用辅助存储,而不需要重新计算

是否有一个构建矩阵的通用过程

这真的取决于你在解决什么问题以及你如何解决它!矩阵通常用于制表,但不一定是矩阵。这里的主要目标是根据需要随时提供子问题的解决方案,它可以存储在数组、矩阵甚至哈希表中

这本经典的书以两种方式演示了杆切割问题的解决方案,其中1D阵列用作辅助存储

例如,如果我们有兴趣使用价值为c1、c2、.cn的硬币来更改货币的数量,那么矩阵的维数应该是多少,每列/每行应该代表什么

如果我没说错的话,你指的是硬币兑换问题的“完全独特的方式进行改变”变体。您需要找到使用给定的一组硬币构造给定金额的总方法。 有一个很棒的视频可以很好地将其分解。它采用自下而上的方法:

假设您需要从给定的硬币子集
c={1,2,10}
取一套空硬币,从
c
中每行添加一枚硬币。下一行每增加一枚硬币。这些列表示子问题。对于
n=1:10
中的
i
,第
i
列表示使用该行硬币可以构造
i
的方式总数:

--------------------------------------------------------
           |0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
--------------------------------------------------------
|{}        |  |   |   |   |   |   |   |   |   |   |    |
--------------------------------------------------------
|{1}       |  | X |   |   |   |   |   |   |   |   |    |
--------------------------------------------------------
|{1, 2}    |  |   |   |   |   |   |   |   |   |   |    |
--------------------------------------------------------
|{1, 2, 10}|  |   |   | Y |   |   |   |   |   |   | Z  |
--------------------------------------------------------
在此表中,
X
表示使用硬币
{1}
构造金额1的方式数,
Y
表示使用硬币
{1,2,10}
表示金额3的方式数,
Z
表示使用硬币
{1,2,10}表示金额10的方式数

单元格是如何填充的

最初,以
0
为首的整个第一列都用
1
s填充,因为无论您拥有多少硬币,对于0的金额,您只有一种方法可以进行更改,即不进行更改。 第一行的剩余部分是空子集
{}
,其中填充了
0
s,因为没有硬币时,您无法更改任何正值。 现在矩阵如下所示:

--------------------------------------------------------
            0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
--------------------------------------------------------
|{}        |1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |  0 |
--------------------------------------------------------
|{1}       |1 | X |   |   |   |   |   |   |   |   |    |
--------------------------------------------------------
|{1, 2}    |1 |   |   |   |   |   |   |   |   |   |    |
--------------------------------------------------------
|{1, 2, 10}|1 |   |   | Y |   |   |   |   |   |   | Z  |
--------------------------------------------------------
现在,我们如何填写
X
?您有两种选择,要么在这个新的超级集合中使用
1
硬币,要么不使用它。如果您没有使用硬币,方法与上面的行相同,即
0
。但是由于
1
可以用来更改金额
1
,我们使用该硬币,从
1
金额中减去
1
,剩下
0
。现在在同一行中查找,
0
的方式,即
X
前面的列,即
1
。因此,将其添加到顶行的金额中,总数为
1
。因此,将此单元格填充为
1

但是,如何确定矩阵的维数,我们如何知道矩阵的每一行/每一列应该代表什么值?也就是说,是否有一个构建矩阵的通用过程

您需要找到表示子问题所需的递归关系和状态(参数数量)。DP的整体思想是避免子问题的重新计算。您只在第一次需要时计算一次子问题,将其存储在内存中,并在需要时引用存储的值。因此,如果希望稍后引用子问题的存储结果,则需要具有唯一标识子问题的键。子问题的状态通常是该键的良好选择。如果子问题有3个参数
x
y
z
,那么元组
(x的值,y的值,z的值)
就是将子问题的结果存储在哈希表中的好键。如果这些值是正整数,则可以使用矩阵,即多维数组,而不是哈希表。让我们发展一下寻找的想法
sort(0, n) = merge(sort(0, n/2), sort(n/2, n))
F(n) = min(F(n-p), F(n-q), F(n-r)) + 1

# Base conditions
F(0) = 0
F(n) = infinity if n < 0
F(n, only p allowed) = F(n-p, only p allowed) 

## Base condition
F(0) = 1   # There is only one way to select 0 coins which is not selecting any coinss
F(n, p and q allowed) = F(n-q, p and q allowed) + F(n, only p allowed)
F(n, p q and r allowed) = F(n-r, p q and r allowed) + F(n,  p and q allowed)
# F(n, i) = with denominations[i] + without denominations[i]
F(n, i) = F(n - denominations[i], i) + F(n, i-1)

## Base conditions
F(n, i) = 1 if n == 0
F(n, i) = 0 if n < 0 or i < 0