一、前言
本人菜鸟一枚,无奈在老师的“坑蒙拐骗”之下报了2020年3月份的蓝桥杯,为了能够让成绩不太难看(主要是因为交了300报名费)
于是发奋图强,修炼内功数据结构与算法
本章介绍
本章内容:我个人对贪心算法的一些认知与理解。为了更生动形象的展现贪心算法,章节内使用了贪心算法的经典问题–背包问题,来理解贪心算法。
二、贪心算法与背包问题介绍
1、贪心算法介绍
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
上面是某搜索引擎给出的介绍。不长不短,皆是精华。简单来说就是:由局部最优达到全局最优。
2、背包问题描述
现在有一个最大容量为100个单位的背包;
有以下7个物品可以选择装载:
占的容量单位分别为{30, 30, 50, 55, 45, 5, 15};
对应的价值分别为{20, 45, 35, 50, 35, 45, 50};
问:在背包容量范围内,如何选择以上物品能使总价值最大化?
解题思路
总价值最大即全局最最优嘛,那我只要保证在背包剩余容量允许的情况每个装进背包的物品都是最优的就行了,那么物品价值最优表现出来的是什么呢?重量最大或最小?价值最大或最小?
显然都不是,是每个物品的性价比,即价值➗重量
ok,既然知道了我们想要的东西(问题的本质问题),那就动手写代码了。
运行结果
代码实现
import java.util.Arrays;
public class GreedyBag {
private int MAX_WEIGHT = 150; // 背包最大容量值
private int[] weights = new int[] {30, 30, 50, 55, 45, 5, 15}; // 物品重量
private int[] values = new int[] {20, 45, 35, 50, 35, 45, 50}; // 物品价值
private void GreedAlgo(int surplus, // surplus:背包剩余空间
int[] weights, int[] values) {
int arrSize = weights.length;
double[] betters = new double[arrSize]; // 性价比数组
int[] indexs = new int[arrSize]; // 序号数组
// 计算性价比,存进数组
for (int i=0; i<arrSize; i++) {
betters[i] = (double) values[i] / weights[i];
indexs[i] = i; // 按当前顺序对每个性价比元素编号(记住现在的下标)
}
System.out.println("排序前");
System.out.println("性价比:" + Arrays.toString(betters));
System.out.println("序号:" + Arrays.toString(indexs));
// 冒泡排序(降序)
double temp = 0;
for (int i=0; i<arrSize-1; i++) {
for (int j=i+1; j<arrSize; j++) {
if (betters[i] < betters[j]) {
// 性价比数组元素排序
temp = betters[j];
betters[j] = betters[i];
betters[i] = temp;
// 对应的序号也跟着调换(这个序号可以理解为每个物品的Key)
int index = indexs[j];
indexs[j] = indexs[i];
indexs[i] = index;
}
}
}
System.out.println("排序后");
System.out.println("性价比:" + Arrays.toString(betters));
System.out.println("序号:" + Arrays.toString(indexs));
// 对质量、价值数组排序
int[] w1 = new int[arrSize];
int[] v1 = new int[arrSize];
int x = 0; // 当前放入物品数量
int countWeight = 0; // 放下的最大重量
int countValue = 0; // 放下的最大价值
for (int i=0; i<arrSize; i++) {
// 注意,此时是从原始的质量/价值数组赋值,那么谁先谁后由之前排序好了的index(Key)数组决定
w1[i] = weights[indexs[i]];
v1[i] = values[indexs[i]];
// 判断剩余背包容量还能不能继续放入剩下的物品
if (w1[i]<=surplus) {
x += 1;
countWeight += w1[i];
countValue += v1[i];
surplus -= w1[i];
System.out.println("质量为"+w1[i]+"价值为"+v1[i]+"的物品被放进背包,性价比为"+betters[i]+" 性价比排名"+(i+1));
}
}
System.out.println("质量价值排序后");
System.out.println("质量:" + Arrays.toString(w1));
System.out.println("价值:" + Arrays.toString(v1));
System.out.println("运行结果");
System.out.println("最优总数量:" + x);
System.out.println("最优总质量:" + countWeight);
System.out.println("最优总价值:" + countValue);
}
public static void main(String[] args) {
GreedyBag greedy = new GreedyBag();
greedy.GreedAlgo(greedy.MAX_WEIGHT, greedy.weights, greedy.values);
}
}
从运行结果中可以看到选择的性价比排名为1-2-3-5,直接跳过了性价比排第4的。所以:
所谓的最优选择是在背包当前剩余容量下的最优选择。
代码中的注释很详细,就不再讲解了。
三、结语
接下来两天会找蓝桥杯往届涉及贪心算法的题目刷刷,然后放到我的博客里,加深印象,加强理解。
最后
跪求JAVA大神救救孩子啊!!!
有参赛经验或者看法的大佬也请评论区给小弟点建议。