学习目标:贪心算法
掌握贪心算法,学习内容:
提示:以后要学的内容
例如:
1、 贪心算法
2、 分而治之算法(递归)
3、 动态规划
4、 暴力解法
内容:
假设一个问题比较复杂,暂时找不到全局最优解,那么我们可以考虑把原问题拆分成几个小问题,分别求每个小问题的最优解,再叠加这些"全局最优解",就"当作"整个问题的最优解了
贪心算法3步走
第一步
明确到底什么是最优解,明确后记录下来
第二步
明确什么是子问题的最优解?再记录再本子上
第三步
分别求出子问题的最优解再堆叠出全局最优解
问题示意
背包问题
有一个背包,最大承受150公斤,现有7个物品,
重量 | 价值 |
---|---|
35 | 10 |
30 | 40 |
60 | 30 |
50 | 50 |
40 | 35 |
10 | 40 |
25 | 30 |
要求怎么使背包背走最多价值的物品?
分析
对于选择的物品有一个总和限制,比如此时的重量,又希望另一个属性综合最大
此时按照我们的算法3步走
- 明确最优解
在重量限制范围内,价值最大的选择,这就是最优解 - 明确子问题的最优解
认为每次选择的当前价值最高的物品,这就是局部最优解 - 分别求出子问题的最优解在堆叠出全局最优解
此时,我们按照每次选择最大的价值的商品,
价值为:50->40->40->35=165
对应的重量为 50+30+10+40=130
// int[][] nums={{35,10},{30,40},{60,30}
// ,{50,50},{40,35},{10,40},{25,30}};
public int[] d( int[][] nums){
//背包最大能装150,int[1][0]为重量 int[1][1]为价值,求价值最大
//我们按照每次选择最大的价值的商品
int[] temp=new int[1];//临时变量
for(int i=0; i<nums.length-1; i++){ //表示趟数,一共arr.length-1次。
for(int j=nums.length-1; j>i; j--){
if(nums[j][1] < nums[j-1][1]){
temp = nums[j];
nums[j] = nums[j-1];
nums[j-1]= temp;
}
}}
//冒泡排序好了,按照价值以小到大
int z=0;
int perice=0;
for (int i=nums.length-1;i>0;i-- ) {
int[] dw=nums[i];
if (z+dw[0]<=150){
z+=dw[0]; perice+=dw[1];
}else {
break;
}
}
int[] maxPerice={z,perice};
return maxPerice;
}
上面使用价值属性策略,如果我们换成重量来选择,每次选择最小的那个,则为:
重量为: 10+25+30+35+40=140,
价值为: 40+30+40+10+35=155
public int[] d1(int[][] nums){
int[] temp=new int[1];//临时变量
for(int i=0; i<nums.length-1; i++){ //表示趟数,一共arr.length-1次。
for(int j=nums.length-1; j>i; j--){
if(nums[j][0] > nums[j-1][0]){
temp = nums[j];
nums[j] = nums[j-1];
nums[j-1]= temp;
}
}}
//排序好了
int z=0;
int perice=0;
for (int i=nums.length-1;i>0;i-- ) {
int[] dw=nums[i];
if (z+dw[0]<=150){
z+=dw[0]; perice+=dw[1];
}else {
break;
}
}
int[] maxPerice={z,perice};
return maxPerice;
}
/**可以优化算法,去除排序,每次取出最小值的重量.
*使用循环计算是否大于150,使用两个变量记录,每次查询的最小值重量和位置,循环查询最小值比之前的值要小,而后计算是否超过了最大值150,超过则退出
**/
这次换成价值密度来计算,没单位重量的价值,使用价值密度来分析,即价值除以重量
重量 | 价值 -> 价值密度 |
---|---|
35 | 10 -> 0.28 |
30 | 40 -> 1.3 |
60 | 30 -> 0.5 |
50 | 50 -> 1 |
40 | 35 -> 0.875 |
10 | 40 -> 4 |
25 | 30 -> 1.2 |
每次都选价值密度最大的:
重量为:10+30+25+50+35=150 每次去除的范围内选择最大的
而价值为:40+40+30+50+10=170
此时我们问题的求解答案为最高
计算出相关的价值密度即可
我们是否能使用每次子问题都使用单位密度去定义呢?
其实不行,特定的方式只适合特定条件最优解
贪心算法的核心问题
使用贪心算法的前提
- 原问题复杂度过高
- 求全局最优解的数学模型难以建立
- 求全局最优解的计算量过大
- 没有太大必要一定要求出全局最优解,"比较优"就行
把原问题分解成子问题
- 按串行任务分
时间串行的任务,按子任务来分解,即每一步都是在前一步的基础上再选择当前的最优解. - 按规模递减分
规模较大的复杂问题,可以借助递归思想,分解成一个小一点点的问题,循环解决,当最后一步的求解完成后就得到了所谓的"全局最优解" - 按并行任务分
该类问题不分先后,可能并行的,可以分别求解,再按照一定规则将其组合后得到最终解.
例题
leetCode: 443 55 435 376