贪心算法解决经典问题

  • 1、贪心算法定义
  • 2、基本思想
  • 3、简单例子
    • 3.1 分配问题
    • 3.2 区间问题
    • 3.3 快乐司机
    • 3.4 排队打水问题

1、贪心算法定义

顾名思义,贪心算法或贪心思想采用贪心的策略,保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。

2、基本思想

通过一系列选择步骤来构造问题的解,每一步都是对当前部分解的一个扩展,直至获得问题的完整解。所做的每一步选择都必须满足:
(1) 可行的:必须满足问题的约束。
(2) 局部最优:当前所有可能的选择中最佳的局部选择。
(3) 不可取消: 选择一旦做出,在后面的步骤中就无法改变了。
举例:
从 1 4 6 9 4 这几个数字中选出三个使得其和最大
先从中选取最大的数字9即求得局部最优解,再依次取出 6 4,最终得到19为全局最优解。

3、简单例子

3.1 分配问题

问题描述:
有一群孩子和一堆饼干,每个孩子有一个饥饿度,每个饼干都有一个大小。每个孩子只能吃最多一个饼干,且只有饼干的大小大于孩子的饥饿度时,这个孩子才能吃饱。求解最多有多少孩子可以吃饱。
输入输出样例:
输入:1 2
输入:1 2 3
输出:2
题解:
因为饥饿度最小的孩子最容易吃饱,所以我们先考虑这个孩子。为了尽量使得剩下的饼干可以满足饥饿度更大的孩子,所以我们应该把大于等于这个孩子饥饿度的、且大小最小的饼干给这个孩子。满足了这个孩子之后,我们采取同样的策略,考虑剩下孩子里饥饿度最小的孩子,直到没有满足条件的饼干存在。
简而言之,这里的贪心策略是,给剩余孩子里最小饥饿度的孩子分配最小的能饱腹的饼干。至于具体实现,因为我们需要获得大小关系,一个便捷的方法就是把孩子和饼干分别排序。这样我们就可以从饥饿度最小的孩子和大小最小的饼干出发,计算有多少个对子可以满足条件。

import java.util.Arrays;
import java.util.Scanner;
public class greedsuanfa {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();//数量System.out.println("请输入"+n+"个孩子的饥饿度:");Scanner sc = new Scanner(System.in);int[] b=new int[n];for(int i=0;i<b.length;i++){b[i]=sc.nextInt();// System.out.print(" " + b[i]);}int t = scanner.nextInt();//数量System.out.println("请输入"+t+"个饼干大小:");Scanner sc1 = new Scanner(System.in);int[] b1=new int[t];for(int i=0;i<b1.length;i++){b1[i]=sc.nextInt();}int result= solusion(b,b1);System.out.println(result);}static int solusion(int[]childran,int[]cookies){// 对每个孩子的饥饿度 和饼干大小进行排序Arrays.sort(childran);Arrays.sort(cookies);// childnum为能吃饱的孩子个数int childnum=0;// 定义两个指针依次对比childran和cookies数组元素// 若cookies元素>=childran数组对应位置元素,childnum++,两个同时向后移动// 若cookies元素<childran数组对应位置元素,指向cookies数组的指针向后移动一位,指向childran数组的指针不动int cookindex=0;  // cookindex指向cookies数组的指针int childindex=0;// 判断是否越界while (childindex<childran.length && cookindex<cookies.length){if (childran[childindex]<=cookies[cookindex]){cookindex++;childindex++;childnum++;}}return childnum;}
}

3.2 区间问题

问题描述:
给定多个区间,计算让这些区间互不重叠所需要移除区间的最少个数。起止相连不算重叠。
输入输出样例:
输入是一个数组,数组由多个长度固定为2的数组组成,表示区间的开始和结尾。输出一个整数,表示需要移除的区间数量。
输入:[ [1,2], [2,4], [1,3]]
输出:1
题解:
在选择要保留区间时,区间的结尾十分重要:选择的区间结尾越小,余留给其它区间的空间就越大,就越能保留更多的区间。
因此,我们采取的贪心策略为,优先保留结尾小且不相交的区间。具体实现方法为,先把区间按照结尾的大小进行增序排序([ [1,2], [1,3], [2,4]]),每次选择结尾最小且和前一个选择的区间不重叠的区间。(第一个默认区间为[1,2],第二个区间 [1,3],第二个区间起始位置小于第一个区间终止位置,因此,两个区间重叠,跳过该区间后,不重叠,因此需要移除的区间数量为1)

import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class greedsuanfa {public static void main(String[] args) {Scanner in=new Scanner(System.in);System.out.println("输入行数");int rows=in.nextInt();//二维数组行数System.out.println("输入列数");int columns=in.nextInt();//二维数组列数int matrix[][] =new int[rows][columns];//定义一个二维数组int b=3;System.out.println("输入矩阵");//从键盘上输入一个二维数组for(int i=0;i<rows;i++){for(int j=0;j<columns;j++){//System.out.println("输入数据");matrix[i][j]=in.nextInt();}}//从键盘上输出一个二维数组for(int i=0;i<rows;i++){for(int j=0;j<columns;j++){System.out.print(matrix[i][j]+" ");}System.out.println();}int result=solution(matrix);System.out.println(result);}static int solution(int[][] matrix){// 按区间结尾大小对区间进行进行升序排序// 重写Comparator方法Arrays.sort(matrix, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {return o1[1]-o2[1];}});int count=1;// 满足条件的区间个数int pre=matrix[0][1];// pre表示当前区间终止位置元素for (int i = 1; i < matrix.length; i++) {if (matrix[i][0]>=pre){count++;pre=matrix[i][1];}}return matrix.length-count;}
}

3.3 快乐司机

问题描述:
 “嘟嘟嘟嘟嘟嘟
  喇叭响
  我是汽车小司机
  我是小司机
  我为祖国运输忙
  运输忙”
  这是儿歌“快乐的小司机”。话说现在当司机光有红心不行,还要多拉快跑。多拉不是超载,是要让所载货物价值最大,特别是在当前油价日新月异的时候。司机所拉货物为散货,如大米、面粉、沙石、泥土…
  现在知道了汽车核载重量为w,可供选择的物品的数量n。每个物品的重量为gi,价值为pi。求汽车可装载的最大价值。(n<10000,w<10000,0<gi<=100,0<=pi<=100)
输入输出样例:
输入第一行为由空格分开的两个整数n w,第二行到第n+1行,每行有两个整数,由空格分开,分别表示gi和pi
输出:
最大价值(保留一位小数)
输入:
5 36
99 87
68 36
79 43
75 94
7 35
输出:
71.3
题解:
先装第5号物品,得价值35,占用重量7,再装第4号物品,得价值36.346,占用重量29,最后保留一位小数,得71.3
注意 此处4号物品总重75,价值94,物品75可拆分

思路
要使所载货物价值最大,可先计算每件物品的单位价值,每次装载单位价值最大的物品得局部最优解

创建n维4列的多维数组arr[n][4]

import java.util.Scanner;
public class happyDri {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();//数量double w = scanner.nextDouble();//重量double[][] arr = new double[n][4];//第3列为:每一个物品的单位重量的价值//第4列为:判断物品是否已经装进车里了,如果装进车里了则为1,还没有装进车为0for(int i=0;i<n;i++){for(int j=0;j<2;j++){arr[i][j]=scanner.nextInt();}}for(int i=0;i<n;i++){arr[i][2]=arr[i][1]/arr[i][0];//每一个物品单位的价值}double result=0;while(w>0){//当车载重大于0的时候,还可以载物品double max=0;int index=0;boolean flag=true;for(int i=0;i<n;i++){//每一次找到单位最大价值的物品且还没有被装进汽车里的if(arr[i][2]>max&&arr[i][3]==0){max=arr[i][2];index=i;flag=false;}}arr[index][3]=1;if(flag){break;}if(w<arr[index][0]){//车的重量小于要载的重量result+=w*arr[index][2];w=0;}else{//车的重量大于等于要载的重量(w>=arr[index][0])result+=arr[index][1];w-=arr[index][0];}}System.out.printf("%.1f",result);}
}

3.4 排队打水问题

问题描述:
 有n个人排队到r个水龙头去打水,他们装满水桶的时间t1、t2…………tn为整数且各不相等,应如何安排他们的打水顺序才能使他们总共花费的时间最少?
输入输出样例:
第一行n,r (n<=500,r<=75)
第二行为n个人打水所用的时间Ti (Ti<=100);
输出:
最少的花费时间
输入:
3 2
1 2 3
输出:
7
题解:
输入:三个人,两个水龙头
三个人装满水桶的时间分别为 1 2 3
输出:最少的花费时间为7
注意 此处的花费时间是每个人所花费的时间总和(打水时间+等待时间)
例如:第一个人花费时间(1+0),打水1分钟,等待0分钟
第二个人花费时间(2+0),打水2分钟,等待0分钟
第三个人花费时间(3+1),打水3分钟,等待1分钟
因此总共花费 1+2+3+1=7分钟
我第一次没搞明白题的意思理解为花费的最短时间:
第一个人和第二个人同时接水 (1分钟,两分钟),第一个人接完花费1分钟,第三个人去接花费三分钟,总共花费4分钟
思路
花费时间=打水时间+等待时间
每次让接水花费时间最短的人去接水
把每个人的等待时间和打水时间加起来就是总时间

// 有n个人排队到r个水龙头去打水,
// 他们装满水桶的时间t1、t2………..tn为整数且各不相等,
// 应如何安排他们的打水顺序才能使他们总共花费的时间最少?
//第一行n,r (n<=500,r<=75)
//第二行为n个人打水所用的时间Ti (Ti<=100);
// 总时间S=装水时间T+等待时间W
import java.util.Arrays;
import java.util.Scanner;public class Line_Water {public static void main(String[] args){Scanner scanner=new Scanner(System.in);int n=scanner.nextInt(); // 有n个人int r=scanner.nextInt(); //r个水龙头int[] t=new int[n];int[] temp=new int[r];for(int i=0;i<n;i++){t[i]=scanner.nextInt();}Arrays.sort(t);int sum=0; // 每个人的总时间int num=0;while(num < n){for(int i = 0; i < r && num < n; i++, num++) {temp[i] =temp[i] + t[num];// 等号右边的temp[i]放的是num个人的等待时间sum += temp[i];// 总时间}}System.out.println(sum);}
}

贪心算法--经典问题(java实现)相关推荐

  1. 贪心算法经典例题3:导弹发射问题

    贪心算法经典例题3:导弹发射问题 问题描述: 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一 ...

  2. 贪心算法经典例题分析

    贪心经典例题 一.区间覆盖问题 例题:洛谷P1803 这是一个非常简单的区间覆盖问题. 针对此类问题,最佳的贪心算法应为将每一个区间的结束时间从小到大排序. 令所选的第 i 个区间的结束时间为 e[i ...

  3. python实现贪心算法经典案例

    均分纸牌问题 python代码: # 贪心算法实现均分纸牌问题 import numpy as npdef avg_Card(cards_list):avg = np.mean(cards_list) ...

  4. 贪心算法经典问题:硬币找零

    这是一个用最少硬币支付指定额度的问题. 一.问题描述:如下图图一,设有6种不同面值的硬币,各硬币的面值分别为5分.1角.2角.5角.1元.2元.现要用这些面值的硬币来购物和找钱.购物时规定了可以使用的 ...

  5. 【刷题日记】贪心算法经典题目

  6. java贪心,java实现贪心算法

    并证明了贪心算法解决此问题的有效性,且进行了实例验证,并进 行了复杂度分析,此算法是解决资源组合规划问题较好的方法. 关键词:贪心算法;java 程序;复杂度分析;...... 数据结构与算法 实验名 ...

  7. 数据结构与算法之美(十四)算法思想——贪心算法

    目录 贪心算法介绍 贪心算法例子 1. 背包 2. 分糖果 3. 钱币找零 4. 区间覆盖 5. 区间覆盖的延伸:任务调度.教师排课 贪心算法经典应用 1. 霍夫曼编码 2. 最小生成树算法 3. 最 ...

  8. java贪心算法几个经典例子_经典算法思想5——贪心(greedy algorithm)

    贪心算法,是指在对问题求解时,总是做出再当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的仅是某种意义上的局部最优解. 贪心算法没有固定算法框架,算法设计的关键是贪心策略的选择.必须注 ...

  9. java经典算法思想 贪心_这几道经典例题帮你轻松搞透贪心算法

    贪心算法概念叙述 运用贪心算法求解问题时,会将问题分为若干个子问题,可以将其想象成俄罗斯套娃,利用贪心的原则从内向外依次求出当前子问题的最优解,也就是该算法不会直接从整体考虑问题,而是想要达到局部最优 ...

  10. 算法基础(Java)--贪心算法

    前言 前面简单的介绍了八大经典排序算法,此文将要介绍贪心算法,并介绍一些常见贪心算法题目. 1. 贪心算法的概念 所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最 ...

最新文章

  1. 剑三 计算机中丢失,剑网3指尖江湖:剑侠情缘中“丢失”的几年,竟在腾讯游戏被找到...
  2. InitializingBean接口使用方法
  3. CodeForces - 1348C Phoenix and Distribution(思维)
  4. Spring远程调用技术1-RMI
  5. React开发(254):react项目理解 ant design 注意参数传递格式
  6. 多路平衡查找树 --- B(B-)树
  7. redis循环键_Redis的并发控制
  8. /bin/sh^M:损坏的解释器: 没有那个文件或目录
  9. Windows Server 2012 R2 VDI系列(四)—创建虚拟桌面集合
  10. C#多线程之线程同步篇2
  11. Java实习生的标准是什么
  12. 95%的人都会答错的类加载的问题
  13. airbnb北京民宿运营情况分析
  14. BetterTouchTool使用指南——TouchBar篇
  15. 怎么在微信小程序中设置密码重置
  16. Spring Boot配置文件---约定大于配置
  17. 领袖的七个非常重要的根性-余世维
  18. PMP有效期三年后,还有必要续证吗?详细续证流程PDU积攒方法
  19. 完整的项目管理流程包括什么?
  20. 计算机学院华北科技学院考研,2019年华北科技学院硕士研究生招生拟录取名单公示...

热门文章

  1. 全球抵押销售点(POS)软件行业调研及趋势分析报告
  2. origin游戏服务器引擎
  3. Visio 2013 永久激活,破解工具在win10下避免自动删除程序文件
  4. pyqt5菜鸟教程_PyQt5教程(一)——第一个PyQt5程序
  5. java周报简单模板_快速成长从写一份走心的周报开始
  6. 我说CMMI2.0之技术解决方案
  7. C语言输出有趣的图形,c语言经典游戏程序源代码大全
  8. java学习(java入门)
  9. 4个免费代码自动生成神器
  10. PostgreSQL命令导入sql文件