接下來學習貪心算法和動態規劃,學習的過程當中因爲看的是錄播,發現老師上課發現人有些沒來有些許失落,下次在沒有肯定有充足時間的狀況下,取消一切網絡課程的報名。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