紧接着上一篇动态规划问题,现在我们开始探讨一个新的问题,问:有一个发现了5个金矿,每一个金矿的储量不同,需要参与挖掘的工人数也不通,参与挖矿工人的总数量是10人,每一座金矿要么全挖,要么不挖,不能派一般人挖一半的金矿,想要得到最多的黄金,应该挖取哪几座金矿呢?金矿1储存500金 需5人,金矿2储存400金需要5人,金矿3储存350金矿需要3人,金矿4储存300人需要4人,金矿5储存200金需要3人

经过上篇爬楼梯的问题,我们已经知道了动态规划的三个核心元素,最优子结构、边界、状态转移方程式,好现在我们就开始分析一下看在五个金矿全部在的情况下 可以分为两个状态1、第五金矿不挖、前四个金矿中挖两个,2第五个金矿选择挖,和前四个金矿选择挖一个 同时人数剩余7人。这个两个结构都是这个大问题的最优子结构 但是这个最优子结构和这个金矿选择有什么关于呢?没错 就是两者选其中最大的一个。

我们将金矿数设置为N,工人数为W,金矿的数量设置为数组G[],金矿的用工量设置为数组p[]。则得到结论:

  F(5,10)=MAX(F(4,10),F(4,10-P[4])+G[4])

ok 现在我们 找到了最优子结构和和状态转移方程式,但是程序的边界是什么呢?这个很简单边界就是只剩下一个金矿可以选择我们必须挖这个唯一的金矿,但是这个时候我们需要满足一个 条件就是剩余的总人数大于挖改矿需要的人数。

同样我们和上篇文章一样我们可以首先开始递归算法。

1、递归算法

/**
*
* @param G 金矿储存量
* @param N 金矿数
* @param W 工人数
* @param P 需要的挖矿人数
* @return
*/
public int getKingGold(int G[],int N,int W,int P[])throws Exception{
if (N>G.length)throw new Exception("金矿数不匹配!");
if(N<=1 && P[0] > W) return 0; //当数量人数少于 需要挖矿的人数时
if (N==1 && P[0]<=W) return G[0]; //最后一个矿时 人数多于需要挖矿的人数
if (N>1 && W < P[N-1])return getKingGold(G,N-1,W,P);
int num1 = getKingGold(G,N-1,W,P);
int num2 = getKingGold(G,N-1,W-P[N-1],P) + G[N-1];
return Math.max(num1,num2);
}

2、备忘录算法


这里要做一个小改动,应为这个是要记录,将剩余人数和剩余金矿数作为的最大值记录下来

public int getKingGoldwithMap(int G[],int N,int W,int P[],Map<Integer,Integer> map)throws Exception{
if (N>G.length)throw new Exception("金矿数不匹配!");
if(N<=1 && P[0] > W) return 0; //当数量人数少于 需要挖矿的人数时
if (N==1 && P[0]<=W) return G[0]; //最后一个矿时 人数多于需要挖矿的人数
if (N>1 && W < P[N-1])return getKingGold(G,N-1,W,P);
DicText obj = new DicText(N,W);
if (map.containsKey(obj.hashCode())){
return map.get(obj.hashCode());
}else{
int num1 = getKingGold(G,N-1,W,P);
int num2 = getKingGold(G,N-1,W-P[N-1],P) + G[N-1];
int result = Math.max(num1,num2);
map.put(obj.hashCode(),result);
return result;
} } private static class DicText{
private int n;
private int w; @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DicText dicText = (DicText) o;
return n == dicText.n &&
w == dicText.w;
} @Override
public int hashCode() {
final int seed = 31;
int num = seed * n +2 ;
num = num * w + 1;
return num;
} public DicText(int n, int w) {
this.n = n;
this.w = w;
} public int getN() {
return n;
} public void setN(int n) {
this.n = n;
} public int getW() {
return w;
} public void setW(int w) {
this.w = w;
}
};

 这里将金矿剩余数和人数的剩余数加在一起做成一个类,并将hashcode值进行重写。

三、动态规划的解法

代码为

public int getMostGold(int n,int w,int []g,int[] p){
int perReuslts []=new int[p.length];
int result [] = new int [p.length];
//填充边界格子的值
for (int i = 0;i<=n ;i++){
if (i<p[0]){
perReuslts[i] = 0;
}else {
perReuslts[i] = g[0];
}
}
//填充其余格子的值,外层循环是金矿的数量,内层循环是人工数
for (int i = 0;i<n ;i++){
for (int j = 0;j<=w;j++){
if (j<p[i]){
result[j] = perReuslts[j];
}else {
result[j] = Math.max(perReuslts[j],perReuslts[j-p[i]] + g[i]);
}
}
}
return result[n];
}

  根据表中的数据可以找到以上规律 可以求出数据。

最新文章

  1. is和as
  2. 第三章 一个简单的机器学习例子让你了解DeepLab的语言风格
  3. Dev WPF使用总结
  4. js中创建数组的方法
  5. [iOS-UI]点击清空按钮,却会有提交的感觉
  6. 简单的bat命令去获取wsdl的源码
  7. 简单SSM配置详解
  8. Wordpress模板制作、改造、设计
  9. [转载] TLS协议分析 与 现代加密通信协议设计
  10. Android问题-DelphiXE8安装后编译Android提示SDK无法更新问题(XE10也可以解决)
  11. sshj ,ssh , springmvc pom.xml
  12. android 遇到的细节 FAQ
  13. Spring boot+CXF开发WebService
  14. 移动webapp的那些bug
  15. permutations II(全排列 2)
  16. window系统中 mongodb创建用户名和密码
  17. C# JSON 转换
  18. 用GDB调试程序(二)
  19. oracle 连接池参数
  20. L215 Visual impairment

热门文章

  1. 安装Nginx:通过yum方式
  2. Matlab filter常用函数
  3. AC3 exponent coding
  4. chrome firefox浏览器屏蔽百度热搜
  5. Redis05——Redis五大数据类型 String
  6. Windows引用opencv静态库
  7. MYSQL实现分组排序并取组内第一条数据
  8. Docker - 命令 - docker volume
  9. unittest 改装框架ascii 排序执行用例,按照自己书写先后顺序执行
  10. Django - 美化显示request.META