貪心算法算是我系統性接觸的第一個算法,在學習的過程中頁也看了一些書籍和示例,接下來介紹貪心的概念以及一個例子:
貪心算法主要的思想是局部最優解。貪心算法在目前已有的信息上做出局部最優解,同時做出了選擇之后,不管將來有什么結果,選擇都不會有所改變,同時,貪心策略的選擇對於算法的好壞有着直接的影響。
貪心算法的特性(滿足后可使用):
1:貪心選擇
指原問題的整體最優解可以通過一系列的局部最優解得出,應用同一規則,將原問題轉化為一個相似但規模更小的子問題,而后每一步都是當前最佳的選擇。這種選擇依賴於已做出的選擇。同時,貪心策略無回溯過程。
2:最優子結構
當一個問題的最優解包含其子問題的最優解時,稱此問題為最優子結構性質。這個性質是該問題能否用貪心解決的關鍵。
貪心算法的使用步驟:
1:制定貪心策略選擇一個當前看上去最好的方案(方案的選擇尤為重要)。
2:根據貪心策略一步一步獲得局部最優解。
3:將所有的局部最優解和成為原來問題的一個最優解。
接下來介紹兩個示例:
1:最優裝載問題:
問題描述:有一艘船,載重量為C,有i件古董,重量分別為Wi,如何盡可能多的裝載古董?
解題思路:將古董重量由大到小排序,然后將其依次裝入船中,當大於船的重量時停止,最終返回轉載的數量。
題目數據:C:30,W:4,10,7,11,3,5,14,2
1 public int Solution1() { 2 int C = 30; 3 int[] W = new int[]{4, 10, 7, 11, 3, 5, 14, 2}; 4 Arrays.sort(W); 5 int tmp = 0; 6 int i = 0; 7 while (tmp <C){ 8 tmp+=W[i]; 9 i++; 10 } 11 return i-1; 12 }//最優裝載問題解法
最后返回值為5,時間復雜度O(n+nlogn)
2:背包問題:
問題描述:山中有一個山洞,洞中n種寶物,每種寶物有一定的重量W和價值V,只能運走M重量的寶物,一種拿一樣,寶物可分割,如何使寶物價值最大?
解題思路:選擇貪心策略單位價值最大寶物,然后從性價比由高到低選擇,最終輸出寶物最大價值。
題目數據:W:4,2,9,5,5,8,5,4,5,5;V:3,8,18,6,8,20,5,6,7,15;M:30
1 public float Solution2(){ 2 int M=30; 3 int[] W=new int[]{4,2,9,5,5,8,5,4,5,5}; 4 int[] V=new int[]{3,8,18,6,8,20,5,6,7,15}; 5 Item[] items=new Item[W.length]; 6 for(int i=0;i<W.length;i++){ 7 items[i]=new Item(W[i],V[i]); 8 }//計算單位重量的價值,並將其存為一個數組 9 Arrays.sort(items); 10 Item[] item =new Item[items.length]; 11 for(int i=0;i<10;i++){ 12 item[i]=items[9-i]; 13 }//數組翻轉 14 float Value=0; 15 int count=0; 16 int tmp=0;//裝載的重量 17 while(tmp<M){ 18 if(tmp+item[count].getW()>M || tmp+item[count].getW()==M){ 19 break; 20 }else{ 21 tmp+=item[count].getW(); 22 Value+=item[count].getV(); 23 count++;} 24 } 25 int m=M-tmp;//剩下的重量 26 Value+=m*item[count].getV1();//拿走分割后的部分 27 return Value; 28 } 29 public class Item implements Comparable<Item>{ 30 private int W;//重量 31 private int V;//價值 32 private float V1;//單位價值 33 public Item(int i1,int i2){ 34 this.W=i1; 35 this.V=i2; 36 this.V1=((float) i2)/i1; 37 } 38 39 public float getV1() { 40 return V1; 41 } 42 43 public int getV() { 44 return V; 45 } 46 47 public int getW() { 48 return W; 49 } 50 51 public int compareTo(Item i){ 52 if (this.V1>i.getV1()){ 53 return 1; 54 55 }else if(this.V1==i.getV1()){ 56 return 0; 57 }else if(this.V1<i.getV1()){ 58 return -1; 59 } 60 return 0; 61 } 62 }
最后返回值為70.5,時間復雜度O(n+nlogn)
在這道題的解題思路中,如果java有c++中的結構體會使后面的代碼不那么冗余,在java中需要實現comparable接口實現對象比較,稍微麻煩了些,但總體解題思路是一樣的。