蓝桥杯算法合集: 蓝桥杯算法合集(终极完结版)
贪心算法:
思想
每一步都采取当前状态下的最优选择 从而希望推出全局最优解
缺点:
用贪心策略求得的不一定是全局最优解。比如换零钱那道题,若换成 25 20 5 1四种面值 按照该算法结果应为 面值25 5 5 5 1一共需要5张,显然不对 。正确结果应该为20 20 1只需要3张即可 。
因为没有遍历全部可能性解,只是当前这一步可以达到的局部最优解,过早做出决定 ,贪图眼前局部利益的最大化 。没有放眼长远未来而是走一步看一步,所以通常作为辅助策略来使用
小知识点:
- 子序列可以不连续 但是相对位置不改变
子串、子数组、子区间必须连续
下面两个知识点是在01背包问题时用上的
- Article类的数组
Article [] articles=new Article[] {
new Article(35,10),new Article(30,40),
new Article(60,30),new Article(50,50),
new Article(40,35),new Article(10,40),
new Article(25,30)
};
- 对article数组按cmp迭代器排序
Comparator<Article> cmp=(Article a1,Article a2)->{return Double.compare(a2.valueOfDensity,a1.valueOfDensity);}
Arrays.sort(articles, cmp);
最优装载问题
问题描述
在北美洲东南部,有一片神秘的海域,那里碧海 蓝天、阳光明媚,这正是传说中海盗最活跃的加勒比海。17 世纪时,这里更是欧洲大陆 的商旅舰队到达美洲的必经之地,所以当时的海盗活 动非常猖獗。有一天,海盗们截获了一艘装满各种各样古董的 货船,每一件古董都价值连城,一旦打碎就失去了它 的价值。
虽然海盗船足够大,但载重量为 30,每件古董的重量分别为 3,5,4,10,7,14,2,11,
海盗们该如何把尽可能多数量的宝贝装上海盗船呢?
package 贪心;
import java.util.Arrays;
public class 最优装载问题 {
public static void main(String[] args) {
Integer[] weights= {3,5,4,10,7,14,2,11};
//从小到大排2 3 4 5 7 10 11 14
Arrays.sort(weights);
// for(int i=0;i<weights.length;i++)
// System.out.println(weights[i]);
int capacity=30,count=0,newWeight=0;
//当前所选古董的总重量比船容量小才进入选古董 否则提前跳出外循环
for(int i=0;i<weights.length&&newWeight<capacity;i++) {
//尝试将古董装上船
newWeight=newWeight+weights[i];
if(newWeight<=capacity) {//满足船的容量则正真装上 计数器加1
count++;
System.out.println(weights[i]);
}
}
System.out.println(count);
}
}
零钱兑换
问题描述
假设有25分、10分、5分、1分的硬币,
先要发给客户41分的零钱,如何办到硬币个数最少?
package 贪心;
import java.util.Arrays;
//用贪心策略求得的不一定是全局最优解
//此题若换成 25 20 5 1四种面值 按照该算法结果应为 面值25 5 5 5 1一共需要5张
//显然不对 正确结果应该为20 20 1只需要3张即可
//因为没有遍历全部可能性解 只是当前这一步可以达到的局部最优解 过早做出决定
//贪图眼前局部利益的最大化 没有放眼长远未来 走一步看一步
//通常作为辅助策略来使用
public class 零钱兑换 {
static void moneyChange(Integer[] a,int money) {
Arrays.sort(a,(Integer a1,Integer a2)->{return a2-a1;});
//25 10 5 1 41
int i=0;
while(i<a.length) {
if(money<a[i]) {//当剩余的钱小于该面值时 i++跳过该面值
i++;
continue;
}
//能执行到这里说明当前剩余的前大于该面值却比上一次面值小 该面值为当前最适
money-=a[i];
System.out.println(a[i]);
}
}
static void moneyChange2(Integer[] a,int money) {
//从小往大排:1 5 10 25
Arrays.sort(a);
int count=0;
for(int i=a.length-1;i>=0;i--) {
if(money<a[i]) {//当所有面值都比剩余的钱大时 结束循环
continue;
}
money-=a[i];
System.out.println(a[i]);
count++;
//选了最大面值之后 还要从最大开开始重新枚举
i=a.length;
}
System.out.println(count);
}
public static void main(String[] args) {
Integer[] faces= {5,10,25,1};
//或者Arrays.sort(faces,(Integer a1,Integer a2)-> a2-a1);
int money=41;
//moneyChange(faces,money);
moneyChange2(faces,money);
}
}
01背包问题
问题描述:
有n件物品,每个物品都有一个大小和价值,给你一个固定容量的背包,要求装的东西价值总和最大
实例:
现在有重量分别为35 30 60 50 40 10 25,价值分别为10 40 30 50 35 40 30的物品,
背包最大承重为150,求该背包所能放置的物品最大价值是多少?
package 贪心;
public class Article {
public int weight,value;
public double valueOfDensity;
Article(int weight,int value){
this.weight=weight;
this.value=value;
this.valueOfDensity=value*1.0/weight;
}
@Override
public String toString() {
return "Article [weight=" + weight + ", value=" + value + ", valueOfDensity=" + valueOfDensity + "]";
}
}
package 贪心;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class _01背包问题 {
//传一个比较器Comparator<Article> cmp 按设定关键字排序
static void select(String title,Comparator<Article> cmp) {
//将物品变量直接封装在成员方法里作为局部变量 就可以不用通过mian方法传参了
Article [] articles=new Article[] {
new Article(35,10),new Article(30,40),
new Article(60,30),new Article(50,50),
new Article(40,35),new Article(10,40),
new Article(25,30)
};
Arrays.sort(articles, cmp);
//将Article类封装到list存储结构
List<Article> selectedArticles=new LinkedList<>();
int capacity=150,weight=0,value=0;
for(int i=0;i<articles.length&&weight<capacity;i++) {
int newWeight=weight+articles[i].weight;
if(newWeight<=capacity) {
weight=newWeight;
value+=articles[i].value;
selectedArticles.add(articles[i]);
}
}
for(int i=0;i<selectedArticles.size();i++) {
System.out.println(selectedArticles.get(i));
}
System.out.println(weight);
System.out.println(value);
}
public static void main(String[] args) {
//价值主导
select("价值主导",(Article a1,Article a2)->{
return a2.value-a1.value;
});
//重量主导
select("重量主导",(Article a1,Article a2)->{
return a1.weight-a2.weight;
});
//价值主导
//a2.valueOfDensity-a1.valueOfDensity;结果为double型 而迭代器要求返回类型为int
//Double.compare(double d1,doouble d2)返回int型
select("价值密度主导",(Article a1,Article a2)->{
return Double.compare(a2.valueOfDensity, a1.valueOfDensity);
});
}
}
使用贪心算法由于其目光短浅,算出来不一定正确,01背包这题用动态规划解,详见:动态规划常见模型之背包专题