紧接着上一篇动态规划问题,现在我们开始探讨一个新的问题,问:有一个发现了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];
}

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

动态规划-国王的金矿问题java的更多相关文章

  1. 动态规划入门——数字三角形(Java)

    动态规划的概念对于新手来说枯燥难懂,就算看懂了,做题的时候依旧抓耳挠腮的毫无头绪,这些比较难理解的算法,还是需要根据例子来一步步学习和理解,从而熟练掌握,下面,咱们就通过一个简单的小例子来学习动态规划 ...

  2. 【Leetcode】国王挖金矿

    参考该文章 https://www.cnblogs.com/henuliulei/p/10041737.html #include <iostream> #include <cstr ...

  3. 动态规划算法的java实现

    一:动态规划 1)动态规划的向前处理法 java中没有指针,所以邻接表的存储需要转化一中形式,用数组存储邻接表 用三个数组u,v,w存储边,u数组代表起点,v数组代表终点,w代表权值;例如:1--&g ...

  4. Java面试题集(136-150)

    摘要:目,尽管仅仅有15道题目.可是包括的信息量还是非常大的,非常多题目背后的解题思路和算法是非常值得玩味的. 136.给出以下的二叉树先序.中序.后序遍历的序列? 答:先序序列:ABDEGHCF.中 ...

  5. 算法-动态规划DP小记

    算法-动态规划DP小记 动态规划算法是一种比较灵活的算法,针对具体的问题要具体分析,其宗旨就是要找出要解决问题的状态,然后逆向转化为求解子问题,最终回到已知的初始态,然后再顺序累计各个子问题的解从而得 ...

  6. java 递归打印20个斐波那契数

    class Test { public static void main(String[] args) { // feibo j=new feibo(); for (int n = 1; n < ...

  7. Java匹马行天下之 Java国出了个Java——举国欢庆

    Java帝国的崛起 前言: 看庭前花开花落,宠辱不惊, 望天上云卷云舒,去留无意. 闹心的事儿,选择释怀: 纠缠的人儿,试着放下, 生活其实很美. 心若向阳,就无惧悲伤. 愿你明朗坦荡纵情豁达,有得有 ...

  8. Java匹马行天下之Java帝国的崛起(大结局)

    Java匹马行天下之Java帝国的崛起大结局 前言: [博客*缘] 网络真情伴, 博客友谊连. 笑中藏泪暖中寒. 回想那些悲喜, 苦涩也缠绵. 往事难回首, 新篇染旧言. 世间多少梦能全. 感谢相牵, ...

  9. Java刷题-tree

    一.分别按照二叉树先序,中序和后序打印所有的节点. 这道题就是书上的算法思想的实际使用,唯一需要特别注意到的是用递归的方式建树,还是比较巧妙的,因为一棵树的建立过程字符流是重复使用的,用递归的方式对根 ...

随机推荐

  1. MySql 怎么存取 Emoji

    01.前言 Emoji 在我们生活中真的是越来越常见了,几乎每次发消息的时候不带个 Emoji,总觉得少了点什么,似乎干巴巴的文字已经无法承载我们丰富的感情了.对于我们开发者来说,如何将 Emoji ...

  2. linux centos7分区

    哈喽! 我今天来分享一下Linux的分区,本次我使用的是LinuxCentos7版本为例,使用虚拟机,命令是fdisk Linux分区有4个主分区及扩展分区,逻辑分区. 首先给虚拟机添加8G硬盘(硬盘 ...

  3. C++转换构造函数和隐式转换函数

    今天是第一次听到C++还有个转换构造函数,之前经常见到默认构造函数.拷贝构造函数.析构函数,但是从没听说过转换构造函数,隐式转换函数也是一样,C++的确是够博大精深的,再次叹服!          其 ...

  4. A task in a suit and a tie:paraphrase generation with semantic augmentation解读

    1.该算法核心:在seq2seq模型的编码器中增加语义的frame 和 roles 2.上图为算法整个流程: 1).首先输入一句话s,SLING会使用frame和role label注释输入语句s,然 ...

  5. (搬运)使用PHPstudy在Windows服务器下部署PHP系统

    原帖地址:http://www.php.cn/php-weizijiaocheng-406175.html 这篇文章主要介绍了关于使用PHPstudy在Windows服务器下部署PHP系统,有着一定的 ...

  6. 在一个C程序中,main()函数可以放在哪?

    C语言规定,在一个C程序中,main()函数的位置(). A.必须在系统调用的库函数之后 B.必须在程序的开始 C.必须在程序的最后 D.可以在任意位置 答案:D [解析] 每个C程序有且只有一个主函 ...

  7. 深入delphi编程理解之消息(五)重写(override)dispatch、wndproc方法和Application.OnMessage事件

    dispatch.wndproc是VCL framework在TWinCtronl定义的虚拟方法,下面程序通过重写(override)这两函数拦截WM_LBUTTONDOWN消息,来与Applicat ...

  8. redis-start

    start CAP BASE: 基本可用 Basically Available 软状态 Soft state 最终一致 Eventually consistent Redis:REmote DIct ...

  9. JAVA 中集合ConcurrentMap

    ConcurrentMap ConcurrentMap,它是一个接口,是一个能够支持并发访问的java.util.map集合 在原有java.util.map接口基础上又新提供了4种方法,进一步扩展了 ...

  10. 会话技术之Cookie

    在无状态的客户端(未登录)下,张三想买手机然后把手机加入购物车,服务器发出添加成功的响应,然后把手机加入ServletContext域里,然后张三想在逛逛别的, 再无状态的客户端(未登录)下,李四想买 ...