题目: 很久很久以前,有一位国王拥有5座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人人数也不同。金矿储量与所需工人数量如下表所示:
如果参与挖矿的工人的总人数是10,每座金矿要么全挖,要么不挖,不能派出一半人挖取一半的金矿。要求用程序求出,要想得到尽可能多的黄金,应该选择挖取哪几座金矿?
编号 | 黄金储量 | 所需人数 |
---|---|---|
1 | 400kg | 5 |
2 | 500kg | 5 |
3 | 200kg | 3 |
4 | 300kg | 4 |
5 | 350kg | 3 |
解决思路:
对于每一个金矿都有挖与不挖两种选择,因此可以利用动态规划的思想将总问题逐步分解成若干个子问题,然后得到最优解,具体步骤如下:
1、 寻找状态转移方程式;
状态转移方程式:设金矿数量为n,工人数量为w,金矿的含金量为数组g[],金矿所需开采人数设为数组p[],设F(n,w)为n个金矿、w个工人时的最优收益函数,则状态状态转移方程式为:
- 问题边界,金矿数为0或工人数为0的情况:
F(n,w)=0(n=0或=0)
; - 当所剩工人不够挖掘当前金矿时,只有一种最优子结构:
F(n,w)=F(n-1,w),(n>=1,w<p[n-1])
; - 常规情况下的两种最优子结构(即挖当前金矿与不挖当前金矿):
F(n,w)=max(F(n-1,w),F(n-1,w-p[n-1]+g[n-1])),(n>=1,w>=p[n-1])
。
2、利用状态转移方程式自底向上求解问题;
- 每一层的求解结果都可以由下层(底层)推导得到,因此可以使用一个表来记录所有已解决的子问题的答案,即而得到最优解,具体看代码实现2
代码实现:
实现1:
- 最简单的实现方式就是使用递归实现,但是其时间复杂度是O(2^n)
/**
* 获得金矿最优权益
* @param w 工人数量
* @param n 可选金矿数量
* @param p 金矿开采所需的工人数量
* @param g 金矿储量
* @return 最优收益
*/
public static int getBestGoldMining(int w,int n,int[] p,int[] g){
if(w==0||n==0){
return 0;