面试中算法(金矿)

有一位国王拥有5座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人人数也不同。

例如,有的金矿储量是5ookg黄金,需要5个工人来挖掘;有的金矿储量是2ookg黄金,需要3个工人来挖掘...... 如果参与挖矿的工人的总数是10。每座金矿要么全挖,要么不挖,不能派出一半人挖取一半的金矿。要求用程序要想得到尽可能多的黄金,应该选择挖取哪几座金矿?

金矿按照性价比从高到低进行排序,排名结果如下:

第1名,350kg黄金/3人的金矿,人均产量约为116.6kg黄金。

第2名,500kg黄金/5人的金矿,人均产量为100kg黄金。

第3名,400kg黄金/5人的金矿,人均产量为80kg黄金。

第4名,300kg黄金/4人的金矿,人均产量为75kg黄金。

第5名,200kg黄金/3人的金矿,人均产量约为66.6kg黄金。

由于工人数量是10人,优先挖掘性价比排名为第1名和第2名的金矿之后,工人还剩下2人,不够再挖掘其他金矿了。

得出的最佳金矿收益是350+500即850kg黄金。
解决思路是使用贪心算法。这种思路在局部情况下是最优解,但是在整体上却未必是最优的。

    如果我放弃性价比最高的350kg黄金/3人的金矿,选择500kg黄 金/5人和400kg黄金/5人的金矿,加起来收益是900kg黄金,是不是大于你得到的850kg黄金?

动态规划,就是把复杂的问题简化成规模较小的子问题,再从简单的子问题自底向上一步一步递推,最终得到复杂问题的最优解。 

10个工人在前4个金矿的收益,和7个工人在前4个金矿的收益+最后一个金矿的收益谁大谁小了。

 首先针对10个工人4个金矿这个子结构,第4个金矿(300kg黄金/4人)可以选择挖与不挖。根据第4个金矿的选择,问题又简化成了两种更小的子结构:

1、10个工人在前3个金矿中做出最优选择。

2、(10-4=6)6个工人在前3个金矿中做出最优选择。

相应地,对于7个工人4个金矿这个子结构,第4个金矿同样可以选择挖与不挖。根据第4个金矿的选择,问题也简化成了两种更小的子结构:

1、7个工人在前3个金矿中做出最优选择。

2、(7-4=3)3个工人在前3个金矿中做出最优选择。

就这样,问题一分为二,二分为四,一直把问题简化成在0个金矿或0个工人时的最优选择,这个收益结果显然是0,也就是问题的边界。
这就是动态规划的要点:确定全局最优解和最优子结构之间的关系,以及问题的边界。

这个关系用数学公式来表达,叫作状态转移方程式。

金矿数量设为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,wzp[n-1])    在常规情况下,具有两种最优子结构(挖当前金矿或不挖当前金矿)。 

 

在上图中,标为橘色的方法调用是重复的。可以看到F (2,7) 、F(1,7)、F (1,2)这几个入参相同的方法都被调用了两次。

当金矿数量为5时,重复调用的问题还不太明显。金矿数量越多,递归层次越深,重复调用也就越多,这些无谓的调用必然会降低程序的性能。 

动态规划的另一个核心要点:自底向上求解。

此时,最后1行最后1个格子所填的900就是最终要求的结果,即5个金矿、10个工人的最优收益是9ookg黄金。 

使用二维数组来代表表格

def get_best_gold(worker,person=[],gold=[]):''':param worker:  工人数量:param person:  金矿开采人数:param gold:  金矿存储量:return:  最优收益'''#初始化表格0r_table=[[0 for i in range(worker+1)] for j in range(len(gold)+1)]double_for(r_table)print('&'*50)#填充表格数据for i in range(1,len(gold)+1):for j in range(1,worker+1):if j<person[i-1]:r_table[i][j]=r_table[i-1][j]else:r_table[i][j] =max(r_table[i - 1][j],r_table[i - 1][j-person[i-1]]+gold[i-1])double_for(r_table)#返回最后一个格子的数据return r_table[len(gold)][worker]def double_for(ll):for row in ll:print(row)if __name__ == '__main__':#采矿人数person=[5,5,3,4,3]#采矿黄金量gold=[400,500,200,300,350]print(get_best_gold(10, person, gold))

      程序利用双循环来填充一个二维数组,所以时间复杂度和空间复杂度都是O ( nw) ,比递归的性能好多啦! 

def get_best_gold2(worker,person=[],gold=[]):'''优化:param worker:  工人数量:param person:  金矿开采人数:param gold:  金矿存储量:return:  最优收益'''#初始化表格0results=[0]*(worker+1)print(results)#填充一维数据for i in range(1,len(gold)+1):for j in range(worker,0,-1):if j>=person[i-1]:results[j] =max(results[j],results[j-person[i-1]]+gold[i-1])print(results)#返回最后一个格子的数据return results[worker]if __name__ == '__main__':#采矿人数person=[5,5,3,4,3]#采矿黄金量gold=[400,500,200,300,350]print(get_best_gold2(10, person, gold))

空间复杂度降低到了O (n)。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/691938.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索人类意识的多样性:从安全感到语感、节奏感的差异

在我们的日常生活中&#xff0c;人类意识表现出多种多样的特点&#xff0c;这些特点往往与个体的天生禀赋和生活经历密切相关。从安全感到语感、节奏感&#xff0c;每个人的表现都有所不同。今天&#xff0c;让我们一起来探索这些差异&#xff0c;感受人类意识的多样性。 首先&…

Excel办公技巧之下拉菜单

在日常办工中&#xff0c;经常需在单元格中输入特定的值&#xff0c;此时我们可以使用下拉菜单解决&#xff0c;输入错误和错误值&#xff0c;可以一劳永逸的解决固定数据输入问题。 使用Excel下拉菜单时&#xff0c;它在数据输入和验证方面发挥着重要作用通过点击单元格的下拉…

资产公物仓管理系统|实现国有资产智能化管理

1、项目背景 资产公物仓管理系统&#xff08;智仓库DW-S201&#xff09;是一套成熟系统&#xff0c;依托互3D技术、云计算、大数据、RFID技术、数据库技术、AI、视频分析技术对RFID智能仓库进行统一管理、分析的信息化、智能化、规范化的系统。 项目设计原则 方案对公物仓资…

HTML标签快速入门

文章目录 一、HTML语法规范1.1 基本语法概述1.2 标签关系 二、HTML基本结构标签2.1 第一个HTML网页2.2 基本结构标签总结 三、网页开发工具3.1 文档类型声明标签3.2 lang 语言种类3.3 字符集3.4 总结 四、HTML常用标签4.1 标签语义4.2 标题标签\<h1> - \<h6>&#…

使用 Spring Boot 配合策略模式增强系统接口扩展能力

使用 Spring Boot 配合策略模式增强系统接口扩展能力 在软件开发中&#xff0c;系统的可扩展性是一个至关重要的方面。而策略模式是一种常见的设计模式&#xff0c;它可以帮助我们实现灵活的算法选择和系统功能扩展。结合 Spring Boot 框架&#xff0c;我们可以更加方便地利用策…

Docker安装教程使用

一、Docker简介 什么是docker&#xff1a; docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上, 也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口什…

c++ 入门2

目录 五. 函数重载 1、参数类型不同 2、参数个数不同 3、参数类型顺序不同 C支持函数重载的原理--名字修饰(name Mangling&#xff09; 为什么C支持函数重载&#xff0c;而C语言不支持函数重载呢&#xff1f; 六. 引用 6.1 概念 6.2 引用特性 6.3 常引用 6.4 使用场景 …

Ps各种修改文字超实用方法

介绍 在日常生活中,难免会遇到进行文字修改的ps场景,此时就需要用到比较专业的ps进行文字修改,博主特意整合了多种情况下的文字p图方法进行记录,但是不包含全部情况,只记录日常中常见的情况,也可以解决大部分场景了 原图有可用文字素材 在p图时,我们可以先观察我们要p的图中…

C++:虚函数表Hook

Hook 在计算机编程中&#xff0c;"Hook"&#xff08;钩子&#xff09;是一种技术&#xff0c;用于拦截并修改特定事件或函数的执行流程。它允许程序员在特定的代码点插入自定义的代码&#xff0c;以实现对程序行为的修改、监视或增强。 虚函数表Hook 虚函数表&#…

哈夫曼编码(上)

文章目录 问题引入哈夫曼编码的编写总述步骤一步骤二步骤三步骤四 实现代码如下 问题引入 哈夫曼编码通常用于通信领域&#xff0c;是对较长信息进行压缩&#xff0c;然后发送到指定的位置&#xff0c;是为了节省发送信息占用的空间。 通常来说&#xff0c;如果信息中字符的重…

如何自定义Linux命令

说明&#xff1a;本文介绍如何将自己常用的命令设置为自定义的命令&#xff0c;以下操作在阿里云服务器CentOS上进行。 修改配置文件 修改配置文件前&#xff0c;先敲下面的命令查看当前系统配置的shell版本 echo $SHELL或者 echo $0区别在于&#xff0c;$SHELL查看的是系统…

合并连个有序链表(递归)

21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 2.讲解算法原理 2.1重复子问题 2.2只关心其中的一个子问题是如何解决的 2.3细节&#xff0c;递归出口 3.小总结 &#xff08;循环&#xff08;迭代&#xff09;VS 递归&#xff09;&#xff08;递归VS深搜&…