贪心思想
在学习数据结构的时候,我们已经见过了贪心思想在Prim和Kruskal中的完美应用,贪心思想因为其的简洁在算法中经常会被用到,有的时候在生活中,我们也会无意中使用到l贪心算法。比如在去shopping时,经常需要进行找零钱的过程,我们总是不自觉的先把大的找出来。
那么什么是贪心思想?
贪心
贪心算法总是作出在当前看来最好的选择,也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。
只有在满足最优子结构的情况下贪心算法得到的结果才是最优结果。
比如找钱的问题,我要给你一百,那么我尽可能每一次给你最多的。
或者比如磁盘的最优存储问题,所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
Prim和kruskal算法都是每次选择最小的边纳入生成树。
从许多可以用贪心算法求解的问题中看到这类问题一般具有两个重要的性质:贪心选择性质和最优子结构性质。
所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这也是贪心问题和动态规划问题的主要区别。
贪心算法的问题
在n行m列的正整数矩阵中,要求从每一行中选一个数,使得选出的n个数的和最大。
可运用贪心策略,选n次,每一次选相应行中的最大值即可。
但是,在一个n*m的方格阵中,每一格子赋予一个数,规定每次移动时只能向上或向右,现试找出一条路径,使其从左下角至右上角所经过的权值之和最大。
同样考虑贪心策略,从左下角向右上角移动,每次移动选择权值较大的一个方向。
3 4 6
1 2 100
以2*3矩阵为例,采用贪心的策略得到的是1,3,4,6和为14但是实际的最优结果为1,2,100,6和为109.
所以说贪心算法并不是总是可行,证明当前问题存在贪心选择性质(全局最优解可以通过局部最优贪心选择达到)和最优子结构性质(问题的最优解包含了其子问题的最优解)。所以贪心问题如果当前的选择不会干扰之后的选择,则不会出现问题。
其他的情况就需要进行证明,证明的最好办法就是将最小子问题进行一步步的合并,直到最后还原为最后的原问题,若所得到的解是总体最优的则可以使用贪心思想,否则不可以。
比如上面的问题,我们的走一步的最优解为1,3,然后我们判断一次走两步的最优解是否任然为1,3这个路径,答案显然不是,变为 1,2,100这个路径,所以显然不能使用贪心思想。
算法实例
假设1元、2元、5元、10元、20元、50元、100元的纸币分别有c0, c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?用贪心算法的思想,很显然,每一步尽可能用面值大的纸币即可。在日常生活中我们自然而然也是这么做的。
public static void main(String[] args) {
int[] coin = {100,50,10,5,1};
Main main = new Main();
int target = 800;
int ci = main.findMoney(target,coin);
System.out.println(ci);
}
public int findMoney(int target,int[] coinType){
int count = 0;
for(int i =0;i<coinType.length;i++){
if(target>=coinType[i]){
int num = target / coinType[i];
target -= num*coinType[i];
count += num;
}
}
return count;
}
有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。
public void testArrangeActivity() {
int[] start = {1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12};
int[] end = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
List<Integer> results = arrangeActivity(start, end);
for (int i = 0; i < results.size(); i++) {
int index = results.get(i);
System.out.println("开始时间:" + start[index] + ",结束时间:" + end[index]);
}
}
public List<Integer> arrangeActivity(int[] s, int[] e) {
int total = s.length;
int endFlag = e[0];
List<Integer> results = new ArrayList<>();
results.add(0);
for (int i = 0; i < total; i++) {
if (s[i] > endFlag) {
results.add(i);
endFlag = e[i];
}
}
return results;
}
部分背包问题, 有n个物体,第i个物体重量为wi,价值为vi,在总重量不超过C的情况下,让总价值尽可能的高。每个物体都可以只取一部分。
我们可以考虑重量和价值的比值作为单价。
- selenium+python自动化77-autoit文件上传
- selenium+python自动化78-autoit参数化与批量上传
- libvirt-内存分配和内存热插拔
- selenium+python自动化79-文件下载(SendKeys)
- selenium+python自动化80-文件下载(不弹询问框)
- libvirt-cpu分配和cpu热插拔
- 如何使用curl调试openstack的api
- selenium+python自动化81-报告优化
- Selenium+python自动化82-只截某个元素的图
- libvirt-TLS加密
- 在openstck中配置使用cloud-init
- libvirt-使用cgroup做资源分割控制
- libvirt-usb设备透传给虚拟机
- Appium+python自动化22-Android夜神模拟器
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PHP设计模式之适配器模式(Adapter)原理与用法详解
- laravel5.5框架的上传图片功能实例分析【仅传到服务器端】
- Laravel5.1框架自带权限控制系统 ACL用法分析
- php使用filter_var函数判断邮箱,url,ip格式示例
- Python json格式化打印实现过程解析
- PHP使用DOM对XML解析处理操作示例
- OpenCV Python实现图像指定区域裁剪
- Laravel框架实现多个视图共享相同数据的方法详解
- python如何快速生成时间戳
- 从python读取sql的实例方法
- PHP+iframe模拟Ajax上传文件功能示例
- Centos7 Yum安装PHP7.2流程教程详解
- PHP session垃圾回收机制实例分析
- thinkphp5框架调用其它控制器方法 实现自定义跳转界面功能示例
- Python常用库Numpy进行矩阵运算详解