特别说明:本文是小编基于罗勇军老师算法竞赛一书中贪心算法章节,对该部分内容进行的理解和总结。
一、基本概念
所谓的贪心算法,就是把整个问题分成多个步骤,在每个步骤中都选取当前步骤的最优方案,直到所有步骤结束。在每一步都不考虑对后续步骤的影响,在后续步骤中也不再回头改变前面的选择。就是“走一步看一步”。
贪心法看起来似乎不靠谱,因为局部最优不一定是全局最优。那么,是否有些规则使得局部最优能达到全局最优?
二、最少硬币问题(引入)
某人带着3种面值的硬币去购物,有1元、2元、5元的,硬币数量不限,他需要支付M元,问:怎么支付使得硬币最少。思路:先拿5元,再拿2元,再拿1元。
package Practice;
import java.util.Scanner;
public class Main {
final static int NUM=3;
final static int[] Value={1,2,5};
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int i,money;
int[] ans=new int[NUM];//记录每种钱的数 ans[0]:1 ans[1]:2 ans[2]:5
money=sc.nextInt();//输入钱数
for(i=NUM-1;i>=0;i--){
ans[i]=money/Value[i];
money=money-ans[i]*Value[i];
}
for(i=NUM-1;i>=0;i--){
System.out.println(Value[i]+"元硬币"+ans[i]);
}
}
但是,在最少硬币问题中,如果稍微改一下参数,就不一定得到最优解,甚至在有解的情况下算不出答案。例如,硬币面值比较奇怪,是1、2、4、5、6元,支付9元,如果用贪心算法,答案6+2+1=9三个硬币,而最优只需4+5两个硬币。用3、5元硬币支付9元,用贪心法无解,而此时我们就需要用到动态规划这一算法(本文不对动态规划进行讲解)。
三、判断一个问题是否能用贪心法
最优子结构性质。当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质,也称此问题满足最优性原理。也就是说,从局部最优能扩展到全局最优。
四、常见问题
(1)活动安排问题
给出节目时间表,如何安排看节目的顺序,能够看更多的节目
下面是航电的一道题,题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2037
3种贪心策略:
1、最早开始时间
2、最早结束时间
3、用时最短
我们很容易发现,第一种策略是错的,因为如果一个活动迟迟不结束,后面的活动无法进行。第三种策略也是错的。采用第二种策略。
解题步骤:
1)把n个活动按结束时间排序
2)选择第1个结束的活动,并删除(或跳过)与它时间相冲突的活动。
3)重复步骤2),直到活动为空。
package Practice;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner (System.in);
int n;
while (true){
n=sc.nextInt();
if(n==0)
break;
int[][] arr = new int[2][n];
for(int i=0;i<n;i++){
arr[0][i]=sc.nextInt();
arr[1][i]=sc.nextInt();
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(arr[1][i]>arr[1][j])
{
int temp=arr[0][i];
arr[0][i]=arr[0][j];
arr[0][j]=temp;
temp=arr[1][i];
arr[1][i]=arr[1][j];
arr[1][j]=temp;
}
}
}
int s;
int count=1;
s=arr[1][0];
for(int i=1;i<n;i++) {
if (arr[0][i] >= s) {
count++;
s = arr[1][i];
}
}
System.out.println(count);
}
}
}
(2)区间覆盖问题
给定一个长度问n的区间,再给出m条线段的左端点和右端点,问最少用多少条线段可以将整个区间完全覆盖。(找尽量长的线段)
解题步骤:
1)把每个线段按照左端点递增排序
2)设已经覆盖的区间是[L,R],在剩下的线段中找出所有左端点小于等于R且右端点最大的线段,把这个线段加入到已覆盖区间里,并更新已覆盖区间的[L,R]值。
3)重复步骤2),直到区间全部覆盖。
(3)最优装载问题
例题:有n种药水,浓度不同,把它们混合起来,得到浓度不大于w%的药水,问怎么混合才能得到体积最大的药水?注意一种药水要么全用,要么都不用,不能只取一部分。
解题思路:题目要求配置浓度不大于w%的药水,那么贪心的思路就是尽量找浓度小的药水。先对药水浓度从小到大排序,药水浓度不大于w%就加入,如果药水浓度大于w%,计算混合后的总浓度,不大于w%就加入,否则结束。
(4)多人接水问题
有n个人排队到m个水龙头去接水,他们装满水桶的时间t1,t1……tn为整数且各不相同,应如何安排他们的接水顺序,才能是他们的总用时间最少,最少是多少?
解题思路:让打水耗时最短的人先接水。
五、视频讲解
基于本文的讲解视频
六、结语
以上是小编整理和总结的一些内容,如有什么错误或遗漏,欢迎大家及时指出和补充。最后,用一句名言作为文章的结尾,送给每一个看这篇博客的人!
知识是一种快乐,而好奇则是知识的萌芽。 —— 培根