LeetCode题解:如何求解金矿问题(动态规划)
题目
很久很久以前,有一位国王拥有5座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人人数也不同。例如有的金矿储量是500kg黄金,需要5个工人来挖掘:有的金矿储量是200kg黄金,需要3个工人来挖掘…
如果参与挖矿的工人的总数是10。每座金矿要么全挖,要么不挖,不能派出一半人挖取一半的金矿。要求用程序求出,要想得到尽可能多的黄金,应该选择挖取哪几座金矿?
总共10个工人,A:400kg黄金/5人 B:500kg黄金/5人 C:200kg黄金/3人 D:300kg黄金/4人 E:350kg黄金/3人
n/w | 1个工人 | 2个工人 | 3个工人 | 4个工人 | 5个工人 | 6个工人 | 7个工人 | 8个工人 | 9个工人 | 10个工人 |
---|---|---|---|---|---|---|---|---|---|---|
400kg黄金/5人 | ||||||||||
500kg黄金/5人 | ||||||||||
200kg黄金/3人 | ||||||||||
300kg黄金/4人 | ||||||||||
350kg黄金/3人 |
解决方法:
贪心算法:依次求得局部最优解,最终得到全局最优解
- 按照金矿的性价比从高到低进行排序,有限选择性价比最高的金矿来挖掘,然后选择性价比第2的…
- 按照贪心算法的思路得出来的最佳金矿收益是350+500即850kg黄金
== 按照这种想法是局部最优,但是全局未必是最优的
动态规划:把复杂的问题简化成规模较小的子问题,再从简单的子问题自底向上一步一步递推
动态规划的要点:确定全局最优解和最优子结构之间的关系,以及问题的边界原问题分解成子问题进行求解(类似于背包问题)
动态规划的状态转移方程式:
我们把金矿数量设为n,工人数量设为w,金矿的含金量设为数组g[ ],金矿所需开采人数设为数组p[ ]. 设F(n, w)为n个金矿、w个工人时的最优收益函数,那么状态转移方程式如下。
F(n,w) = 0 (n=0或w=0)
问题边界,金矿数为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])
在常规情况下,具有两种最优子结构(挖当前金矿或不挖当前金矿)。
相同的颜色代表了方法被传入相同的参数
自底向上求解
w < p[n-1] : F(n,w)= F(n-1,W) (n≥1, w<p[n-1])
w ≥ p[n-1] : F(n,w) = max(F(n-1,w), F(n-1,w-p[n-1])+g[n-1])
例如:F(2,10) = max(F(2-1,10),F(2-1,10-5)+500) = max(F(1,10),F(1,5)+500) = max(400,400+500) = 900
n/w | 1个工人 | 2个工人 | 3个工人 | 4个工人 | 5个工人 | 6个工人 | 7个工人 | 8个工人 | 9个工人 | 10个工人 |
---|---|---|---|---|---|---|---|---|---|---|
400kg黄金/5人 | 0 | 0 | 0 | 0 | 400 | 400 | 400 | 400 | 400 | 400 |
500kg黄金/5人 | 0 | 0 | 0 | 0 | 500 | 500 | 500 | 500 | 500 | 900 |
200kg黄金/3人 | 0 | 0 | 200 | 200 | 500 | 500 | 500 | 700 | 700 | 900 |
300kg黄金/4人 | 0 | 0 | 200 | 300 | 500 | 500 | 500 | 700 | 800 | 900 |
350kg黄金/3人 | 0 | 0 | 350 | 350 | 500 | 550 | 650 | 850 | 850 | 900 |
- 代码实现:
package some_problem;
/*** Copyright (C), 2019-2020* author candy_chen* date 2020/7/30 16:00* version 1.0* Description: 测试*//****/
public class GetBestGoldMining {/*** 获得金矿最优收益* @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;}if (w<p[n-1]){return getBestGoldMining(w,n-1,p,g);}return Math.max(getBestGoldMining(w,n-1,p,g),getBestGoldMining(w-p[n-1],n-1,p,g) + g[n-1]);}/*** 获得金矿最优收益* @param w 工人数量* @param p 金矿开采所需的工人数量* @param g 金矿数量* @return*///递归做了很多重复的计算,当金矿越来越多,递归层次越来越深,重复调用也就越来越多,无谓的调用必然会降低程序的性能//利用双循环来填充一个二维数组,时间复杂度和空间复杂度都是O(nw)public static int getBestGoldMiningV2(int w,int[] p,int[] g){//创建表格int[][] resultTable = new int[g.length+1][w +1];//填充表格for (int i =1;i<= g.length;i++){for (int j=1;j<=w;j++){if (j<p[i-1]){resultTable[i][j] = resultTable[i-1][j];}else{resultTable[i][j] = Math.max(resultTable[i-1][j],resultTable[i-1][j-p[i-1]] + g[i-1]);}}}//返回最后1个格子的值return resultTable[g.length][w];}// 并不需要保存整个表格,无论金矿多少座,我们只保存1行的数据即可,在计算下一行时,要从右向左统计,把旧的数据一个一个替换掉//时间复杂度是O(nw) 空间复杂度是O(n)/*** 获得金矿最优收益* * @param w 工人数量* @param p 金矿开采所需的工人数量* @param g 金矿数量* @return*/public static int getBestGoldMiningV3(int w,int[] p,int[] g){//创建当前结果int[] results = new int[w+1];//填充一维数组for (int i=1;i<= g.length;i++){for (int j=w;j>=1;j--){if (j>=p[i-1]){results[j] = Math.max(results[j],results[j-p[i-1]] + g[i-1]);}}}//返回最后一个格子的值return results[w];}public static void main(String[] args) {int w = 10;int[] p = {5,5,3,4,3};int[] g = {400,500,200,300,350};System.out.println("最优收益:" + getBestGoldMining(w,g.length,p,g));}
}
说明:作者根据网络资料进行搜索学习,理解整理 若有侵权联系作者
参考:程序员小灰
LeetCode题解:如何求解金矿问题(动态规划)相关推荐
- LeetCode题解 - 动态规划-股票买卖
LeetCode题解 - 动态规划-股票买卖 文章目录 LeetCode题解 - 动态规划-股票买卖 **一.穷举框架** **二.状态转移框架** **三.秒杀题目** 121. 买卖股票的最佳时机 ...
- leetcode 题解 (500-1000题,持续更新,part 2)
part1(1-500), part3(1000-*) 502. IPO 题意:给定k,w,profits数组和capital数组.k表示最多可完成的任务数.w是初始资本.profits是各个任务的收 ...
- LeetCode部分习题解答记录-动态规划
LeetCode部分习题解答记录-动态规划 动态规划 120.三角形最小路径和 方法:递归+记忆化 方法2:DP 64.最小路径和 方法1:递归 方法2:DP 从终点到起点,逐步更新 从起点到终点,逐 ...
- leetcode题解131-分割回文串
问题描述 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 .返回 s 所有可能的分割方案. 回文串 是正着读和反着读都一样的字符串. 示例 1: 输入:s = "aa ...
- 算法与数据结构+LeetCode题解-Js版
LeetCode题解Js版 https://webbj97.github.io/leetCode-Js/ 题外话 LeetCode题解:传送门 前端笔记:传送门 项目背景 旨在提高自己对算法的理解,将 ...
- 【LeetCode题解】347_前K个高频元素(Top-K-Frequent-Elements)
更多 LeetCode 题解笔记可以访问我的 github. 文章目录 描述 解法一:排序算法(不满足时间复杂度要求) Java 实现 Python 实现 复杂度分析 解法二:最小堆 思路 Java ...
- 900 多道 LeetCode 题解,这个 GitHub 项目值得 Star!
转自 | 码农有道 大家好,我是小 G. 周末风和日丽,适合刷 LeetCode 今天给你们推荐个 GitHub 项目,里面收集了 900 多道 LeetCode 题解,并包含中英文两个版本,适合大多 ...
- PHP版Leetcode题解开始随缘更新
2019独角兽企业重金招聘Python工程师标准>>> PHP版Leetcode题解 我叫skys215,是一名bug工程师. 我接触编程的时间比较早,但是因为我数学不好加上比较懒, ...
- [LeetCode 题解]: Binary Tree Preorder Traversal
前言 [LeetCode 题解]系列传送门: http://www.cnblogs.com/double-win/category/573499.html 1.题目描述 Given a binary ...
- LeetCode 题解汇总
为什么80%的码农都做不了架构师?>>> LeetCode 题解汇总 转载于:https://my.oschina.net/michao/blog/801863
最新文章
- 跟刘强东、雷军等大佬聊天后,我总结了:如何结交牛人,跟大咖做朋友!
- AI领域的人才短缺,原因是什么?该如何解决?
- Java学习_day004:Scanner与分支结构
- 0-100之间的素数、判断素数的基本和优化方法
- 每秒8.8亿次请求!让数据存得起,看得见 - 云原生多模数据库Lindorm 2020双十一总结
- 【MFC】带下拉菜单的工具栏
- 适用于高级Java开发人员的十大书籍
- 【LeetCode笔记】剑指 Offer 59 - II. 队列的最大值(Java、辅助队列)
- python access 源码_连接的微软Access数据库,这是一个轻量级的Python模块(MDB格式)...
- Adobe Reader PDF 护眼设置
- [bzoj4945][Noi2017]游戏
- NDP调查:P2P下载的视频中60%为情色内容
- ROS 端口IP映射 动态IP映射
- 电源控制环稳定性基础理论与调试方法
- Vultr与阿里云结合自动换IP的解决方案
- 仿支付宝输入密码效果
- 关于使用手机电池替换3节干电池的尝试
- 什么是机器学习?简单理解
- C# Chart 波形显示,动态数据滑动显示方法
- 苹果如何做ASO优化?优化的主要思路有哪些?
热门文章
- 安装ubuntu20.04, CUDA11.4, cnDNN, tensorflow, pytorch
- CAD编辑器图片转换为CAD的方法
- 第二届 “国信蓝点”软件设计大赛 C语言模拟题(附程序题 解题程序)
- 业务流程图怎么画?3步+8张案例,5分钟教你快速上手!
- 关于排列组合的一点点自己的见解
- ROS | Gazebo仿真—阿克曼(Ackermann)四轮小车模型
- 解决win10(联想电脑)自动删除一些破解文件
- O2OA V4.3763 稳定版发布,Java 办公开发平台迎来大量更新
- 【渝粤题库】广东开放大学 形成性考核 - 副本 (13)
- Linux -- Ubuntu 修改Home目录下的中文目录为英文