接下来学习贪心算法和动态规划,学习的过程当中因为看的是录播,发现老师上课发现人有些没来有些许失落,下次在没有肯定有充足时间的状况下,取消一切网络课程的报名。html
贪心算法在求解某个问题时,老是作出眼前的最大利益,也就是说只顾眼前不顾大局,因此他是局部最优解。
贪心算法不是对全部问题都能获得总体最好的解决办法,关键是贪心策略的选择,选择的贪心策略必须具有无后效性,即某个状态之前的状态不会影响之后的状态,只与当前状态有关。java
贪心算法两个重要的特色是:
(1)贪心策略
(2)经过局部最优解可以获得全局最优解算法
有N个同等级的会议须要在同一天使用同一个会议室,如今给出这N个会议的开始时间和结束时间,怎么样才能使会议室最大利用,安排最多场次的会议?数组
分析:这个问题须要用到贪心算法,即先将这些会议根据结束时间天然排序,确定是先安排最早结束的,若是最早安排最后结束的,那若是一个会议开的好久,那原本能够多安排几场结果全被这个占了,显然不是最优的选择,所以优先安排会议先结束的才是合理的。而后接着在剩余的场次里判断会议开始时间是否在当前会议结束时间以后,若是在后面说明能够继续安排,下面就是代码实现。网络
(1)定义会议实体类,须要实现Comparable接口。ide
1 /** 2 * 会议类,需实现Comparable接口 3 */ 4 public class Meeting implements Comparable<Meeting>{ 5 //定义会议属性 6 private int number; 7 private int starTime; 8 private int endTime; 9 10 //get set方法 11 public int getNumber() { 12 return number; 13 } 14 15 public void setNumber(int number) { 16 this.number = number; 17 } 18 19 public int getStarTime() { 20 return starTime; 21 } 22 23 public void setStarTime(int starTime) { 24 this.starTime = starTime; 25 } 26 27 public int getEndTime() { 28 return endTime; 29 } 30 31 public void setEndTime(int endTime) { 32 this.endTime = endTime; 33 } 34 35 //构造方法 36 public Meeting(int number, int starTime, int endTime) { 37 this.number = number; 38 this.starTime = starTime; 39 this.endTime = endTime; 40 } 41 42 @Override 43 public String toString() { 44 return "Meeting{" + 45 "number=" + number + 46 ", starTime=" + starTime + 47 ", endTime=" + endTime + 48 '}'; 49 } 50 //须要重写接口的方法 51 @Override 52 public int compareTo(Meeting o) { 53 //按照会议结束时间升序排列 54 if(this.endTime>o.endTime){ 55 return 1; 56 } 57 if(this.endTime<o.endTime){ 58 return -1; 59 } 60 return 0; 61 } 62 }
(2)测试类,里面实现动态规划算法。学习
1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.List; 4 import java.util.Scanner; 5 6 /** 7 * 贪心算法,用来解决会议安排问题 8 */ 9 public class Greedy { 10 11 public static void main(String[] args) { 12 //获得会议信息 13 Scanner scan=new Scanner(System.in); 14 System.out.println("请输入会议数量"); 15 int count=scan.nextInt(); 16 List<Meeting> list=new ArrayList<Meeting>(); 17 for (int i = 0; i < count; i++) { 18 int starTime=scan.nextInt(); 19 int endTime=scan.nextInt(); 20 Meeting m=new Meeting(i,starTime,endTime); 21 list.add(m); 22 } 23 System.out.println("会议信息"); 24 for (Meeting meeting : list) { 25 System.out.println(meeting); 26 } 27 //贪心策略:按照会议结束时间排序,优先安排最早结束的 28 //而后接下来从后面的会议里,寻找会议开始时间在当前会议结束时间以后的 29 Collections.sort(list); 30 int currentMeetingEndTime=0; 31 System.out.println("贪心算法后会议安排"); 32 for (int i = 0; i <count; i++) { 33 //判断会议结束时间 34 Meeting m=list.get(i); 35 if(m.getStarTime()>=currentMeetingEndTime){ 36 System.out.println(m); 37 //更新当前会议结束时间 38 currentMeetingEndTime=m.getEndTime(); 39 } 40 } 41 } 42 }
控制台输出结果,输入会议后,先按照会议结束时间天然排序,所以首先安排6点-9点场,而后应该是8点-10点场,发现会议开始时间在上一场结束时间以前,所以不安排。继续判断下一场11点-12点场,发现其会议开始时间在上一场以后,所以安排,最后一场同理,所以结果是OK的。测试
动态规划核心思想:分解子问题,经过局部最大值获得全局最大,须要用到表格的分析。this
小偷去商店盗窃,背里有一个包,容量是50kg,如今有以下的物品(物品不能拆分,数量均为1),请问小偷应该怎么样拿才能获得最大的价值?spa
物品1 重量10kg 价值60元
物品2 重量20kg 价值100元
物品3 重量40kg,价值120元
分析:这个问题须要使用动态规划,先将上述问题缩小10倍,能够将背包进行拆分,当背包从1kg到5kg,而后物品从第一个到第三个,看能放的最大价值。
(1)放入第一个物品:背包为1kg时,能够放进去,价值最大就6元,当背包容量达到2之后,依然只有一个物品能够放,所以能获得的最大价值都是6元。
(2)放入第二个物品:背包为1kg时,虽然有第二个物品的选择,可是依然只能放进去第一个物品,所以最大价值依然是6,当背包容量达到2kg时,这个时候有小偷有两种选择,选择不放入第二个物品,这样它依然是6元,选择放入第二个物品,拿出第一个物品,这样价值变成10元,比较后选择后者,所以最大价值就是10元。当背包达到3kg时,同样判断,他能够选择放第一个物品,还有放第二个物品+第一个物品,因此变成16,之后按照此推均为16元。
(3)放入第三个物品:跟前面同样,当背包容量没达到4kg时,小偷只能选择上一个背包重量下最佳选择。当背包达到4kg时,他又有两种选择,选择上一次最佳选择16元,或者丢弃上一次最佳选择,换成装进去一个4kg的物品,这样价值为12元,比较后仍是选择前者,所以4kg下最优就是16。当背包达到5kg时,就会比较16和18,最终选择18。
如下是代码实现。
1 /** 2 * 背包问题,使用动态规划,即分解子问题,经过局部最大值,逐渐获得全局最大值 3 */ 4 public class DP { 5 6 public static void main(String[] args) { 7 //物品重量和价值,一一对应 8 int[] weight=new int[]{10,20,40}; 9 int[] value=new int[]{60,100,120}; 10 //背包容量50kg 11 int capacity=50; 12 //物品个数 3个 13 int count=3; 14 //根据表格分析,建立二维数组 15 int[][] packageValue=new int[count+1][capacity+1]; 16 17 //动态规划分析,判断每一个格子的最大值 18 for (int i = 1; i <=count; i++) {//外层循环表明放第几个物品 19 for (int j = 1; j <= capacity; j++) {//内层循环表明背包重量逐渐增长 20 //根据上述表格的分析,获得以下逻辑 21 if(weight[i-1]<=j){ 22 //比较没放这个物品时,上一轮的这个背包重量下最大价值,和放上这个物品时的最大价值 23 //放上这个物品后,还要考虑剩余背包是否能容纳物品 24 packageValue[i][j]=Math.max(packageValue[i-1][j],value[i-1]+packageValue[i-1][j-weight[i-1]]); 25 }else{ 26 //背包没达到能容纳的重量,就仍是按照上一轮最大价值 27 packageValue[i][j]=packageValue[i-1][j]; 28 }
29 } 30 } 31 32 //打印结果 33 System.out.println("动态规划后最大的价值是:"+packageValue[count][capacity]); 34 } 35 }
控制台输出状况,显然是如今物品1和物品3价值最大,结果OK。
(1)贪心解决不了就用动态规划,通常贪心算法的时间复杂度为O(nlgn),动态规划为O(n^2),能用贪心解决就不用动态规划。
(2)贪心获得的结果不必定是最优解。
(3)动态规划在分析子问题的时候,会使用前面子问题的最优结果,而且前面子问题的最后结果不受后面的影响,最后一个子问题即最优解。
参考博文:
(1) http://www.javashuo.com/article/p-tpuatagz-e.html