算法:动态规划解决<国王和金矿>

问题

有一个国家发现了5座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人数也不同,具体见图。参与挖矿工人的总数是10人。每座金矿要么全挖,要么不挖,不能派出一半人挖取一半金矿,每个人也只会最多挖一次矿。要求用程序求解出,要想得到尽可能多的黄金,应该选择挖取哪几座金矿?


思考

想要方法简单,还是需要通过动态规划思想去分析问题。动态规划核心思想有如下三要素:

  1. 确定最优子结构
  2. 确定状态转移方程
  3. 确定边界

问题分析:

1. 确定最优子结构

挖5个矿最优,也就是挖4个矿最优和是否挖最后一个矿的总金量的大着,用图表示如下:


第1种最优子结构是10个人挖4个矿,剩下的1个矿不挖
第2种最优子结构是满足需求的人挖剩余的1个矿,其它人在4个矿种挖,以图示例,350金/3人作为剩余的矿(当然也可以任选一个矿作为剩余的),那么就是7个人在挖4个矿,3个人挖350金的矿。
F(5,10) = MAX(F(4,10), F(4,7)+350)
对于4个矿最优当然就是3个矿最优和剩余的1个矿是否挖的大着,依次类推

2. 确定状态转移方程

设矿有n个,矿工有w个,含金量用g[]表示,每个矿需要的人数用p[]表示,以示例种数据为例,上述表示分别为:n=5,w=10,g[] = {400,500,200,300,350},p[] = {5,5,3,4,3},当然g和p的内部数据顺序随意,只要g和p对应即可。
状态转移方程:
F(n,w) = MAX(F(n-1,w), F(n-1,w-p[n-1]) + g[n-1]) ,(w >=p[n-1],表示有足够人力挖剩余的矿)
F(n,w) = F(n-1,w) ,(w < p[n-1],人数不足挖剩余的1个矿,故只能在前面的矿种挖)

3. 确定边界

F(1) = g[0] ,(w>=p[0])
F(1) = 0 ,(w < p[0])

状态已经明确,接下来各种解法。

解法1:简单递归

public static void main(String[] args) {
    Solution solution = new Solution();
    // 内部顺序随意
    int[] gold = new int[]{350, 400, 500, 200, 300};
    int[] goldPerson = new int[]{3, 5, 5, 3, 4};
    System.out.println(solution.getMaxGold(5, 10, gold, goldPerson));
}

static class Solution {
    // 算法方法
    int getMaxGold(int n, int w, int[] g, int[] p) {
        if (n == 1 && w < p[0]) {
            return 0;
        } else if (n == 1) {
            return g[0];
        }
        int a = getMaxGold(n - 1, w, g, p);
        if (w < p[n - 1]) return a;

        int b = getMaxGold(n - 1, w - p[n - 1], g, p) + g[n - 1];

        return Math.max(a, b);
    }
}

计算结果为900
复杂度分析:
时间复杂度:O(2n),这种调用也呈二叉树形式

你可能感兴趣的:(算法:动态规划解决<国王和金矿>)