1 - 如果你在编写ACM代码,请避免使用动态分配/ new
。它会使程序变慢,也容易导致段错误。尝试通过查看问题陈述中的边界来静态分配所有内容。
2 - 你想要解决的问题是背包问题。如果愿意,现在可以在互联网/维基百科上找到大量资源和解决方案。
3 - 动态规划的关键在于使用缓存,只需要计算递归函数的值一次。在你的情况下,有2^n种可能的石头分割方式,但假设每个石头的最大重量为W,则一组石头只有n*W种可能的重量。
那么,我们能否制定一个函数F(w),确定是否存在一组石头使它们的总重量为w?如果可以,我们就可以找到一个算法,只需要n*W次迭代,而不是2^n次!
答案是肯定的!但你可能需要进行一些排序才能使其正常工作。让G(w, n)由以下定义:
G(w, n) =
(true, s) if there is some set s containing only from the first n stones
that adds up to w
(false, _) if there is no such set.
现在我们需要计算G(w, NROCKS)以找到F(w)!很容易找到一个递归定义来计算G:
G(0, 0) = (true, {})
G(W, 0) = (false, _)
G(W, N) =
G(W, N-1) //we don't use the N-th rock -
//find solution with remaining rocks instead.
OR G(W - w(N), N-1) //if we use the N-th rock, assumin its wheigh is given by w(N)
//our problem reduces to seeing if it is possible to add up to
// W - w(N) using only the remaining rocks
虽然您可以直接实现此功能,但其运行时间仍然是指数级的(我不会解释这一点。但是请想想传统的斐波那契函数示例)。
使用DP的诀窍在于准确地注意到我们将为此函数使用有限数量的输入(从0到NROCKS * max(MAXWEIGHT)的W和从0到NROCKS的N),因此我们可以使用NROCKS * MAXWEIGHT乘以NROCKS矩阵(或类似物)作为查找表,以避免重复计算。
std::vector<int>
代替动态分配的int
数组来简化代码。 - Frerich Raabe