动态规划是一个经典的问题,在算法实现时经常需要会用到这个思想,黄金矿工是动态规划的景点问题,下面就详细讨论这个问题,如下图所示:
矿产编号 | 钻石储量 | 所需工人数量 |
---|---|---|
1 | 400 | 5 |
2 | 500 | 5 |
3 | 200 | 3 |
4 | 300 | 4 |
5 | 350 | 3 |
我们计算在有m人时,能挖掘的最大价值的黄金,最后得到下表
矿产编号n | m=1 人 | m=2 人 | m=3 人 | m=4 人 | m=5 人 | m=6 人 | m=7 人 | m=8 人 | m=9 人 | m=10 人 |
---|---|---|---|---|---|---|---|---|---|---|
矿产1 | 0 | 0 | 0 | 0 | 400 | 400 | 400 | 400 | 400 | 400 |
矿产2 | 0 | 0 | 0 | 0 | 500 | 500 | 500 | 500 | 500 | 900 |
矿产3 | 0 | 0 | 200 | 200 | 500 | 500 | 500 | 700 | 700 | 900 |
矿产4 | 0 | 0 | 200 | 300 | 500 | 500 | 500 | 700 | 800 | 900 |
矿产5 | 0 | 0 | 350 | 350 | 500 | 550 | 650 | 850 | 850 | 900 |
通过以上的计算过程,我们不难发现,除第一个矿产的相关数据,表格中的其他数据都可以由前一行的一个或两个格子推导而来。例如,3 个矿产 8 个人挖掘的钻石量 F(3,8) 就来自 2 个矿产 8 个人挖掘的钻石量 F(2,8)和 2 个矿产 5 个人挖掘的钻石量 F(2,5),即 F(3,8)=max{F(2,8),F(2,5)+200}=max(500,500+200)=700。
这样我们就可以写如下代码来复现上述实现过程(使用python3实现):
def goldMine(n,w,g,p):
dp = [[0 for _ in range(n+1)] for _ in range(w)]
for i in range(1,n+1):
if i<p[0]:
dp[0][i] = 0
else:
dp[0][i] = g[0]
for i in range(1,w):
for j in range(1,n+1):
if j<p[i]:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - p[i]] + g[i])
return dp
dp = goldMine(10, 5, [400,500,200,300,350], [5,5,3,4,3])
for i in range(len(dp)):
print(dp[i])
最后打印结果:
[0, 0, 0, 0, 0, 400, 400, 400, 400, 400, 400]
[0, 0, 0, 0, 0, 500, 500, 500, 500, 500, 900]
[0, 0, 0, 200, 200, 500, 500, 500, 700, 700, 900]
[0, 0, 0, 200, 300, 500, 500, 500, 700, 800, 900]
[0, 0, 0, 350, 350, 500, 550, 650, 850, 850, 900]