貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的是在某種意義上的局部最優解。
貪心算法還是比較好理解的一個算法,以前我也是這樣認為的,感覺貪心就是每一步都做到最優解就可以了,但是后來結合問題發現自己的理解存在着一些問題。貪心算法比較經典的題目之一就是單源最短路徑問題,這個問題在一些步驟上面我想了很久,有些細節想不通。這個問題以后有機會再講。本次講一講背包問題。
背包問題就是有若干物品,每個物品有自己的價值和重量。背包有總重量。問題就是怎樣將背包裝的最大價值。背包問題也分很多種,貪心算法解決的是物品可以拆分的背包問題(就是物品可以分成幾份裝入)。這個問題用貪心還是比較好解決的。貪心選擇是指所求問題的整體最優解可以通過一系列局部最優的選擇,即貪心選擇來達到。這是貪心算法可行的第一個基本要素,也是貪心算法與動態規划算法的主要區別。此問題就是將每次的放入看成每一步,要想解決問題,就是將每一步都放入最優解。也就是說,每一次的放入都要放入最佳的選擇。講到這里,就要說一說最佳的選擇,每一次的放入的最佳的選擇就是每次放入的物品都是剩余的物品中價值最大且質量最小的,這里就要引入一個物品的屬性,物品的權重值。物品的權重值就是指物品的價值除以物品的質量。所以,本問題的每一次的最佳選擇就是每次都選出權重值最大的物品。
問題的大致思路說完了,下面就講一講具體的算法。算法最開始是先聲明物品類,因為后面要用到很多的物品屬性,如果使用數組會有點麻煩,物品的屬性有背包ID,物品價值,物品質量,物品權重值。在聲明的時候,只要輸入物品的前三個屬性就可以了,物品的權重值可以由前三個推導出來。算法的接下來就是將物品的數組按物品的權重值排序,權重值大的排在數組的前面,方便后面的運算。算法的主體就是從數組中取出物品對象,計算比較物品的質量和當前背包剩余重量的大小,如果大於,就計算要放入的百分比。如果小於,就進行下一步的最佳選擇。算法的大致思路及時這樣。下面粘貼代碼:
1 package sf; 2 3 import java.util.Scanner; 4 5 public class demo6 6 { 7 //選擇排序將數組中的bag按權重排序 8 public static void sort(Bag[] p) 9 { 10 Bag t; 11 for(int i=0;i<p.length;i++) 12 { 13 int max=i; 14 t=p[i]; 15 for(int j=i;j<p.length;j++) 16 { 17 if(t.wi<p[j].wi) 18 { 19 t=p[j]; 20 max=j; 21 } 22 } 23 t=p[i]; 24 p[i]=p[max]; 25 p[max]=t; 26 27 } 28 } 29 //背包問題(貪心算法) 30 public static void bq(Bag[] p,int k,int w,double v) 31 { 32 if(p[k].weight<w) 33 { 34 v=v+p[k].value; 35 System.out.println(p[k].pid+"全部裝入,當前背包價值為"+v); 36 w=w-p[k].weight; 37 bq(p, k+1, w, v); 38 }else{ 39 double a=w*p[k].wi;//當前價值 40 v=v+a; 41 System.out.println(p[k].pid+"裝入了"+((double)w/p[k].weight)+",當前背包價值為"+v); 42 } 43 44 } 45 public static void main(String args[]) 46 { 47 System.out.println("請輸入背包的容量w和物品的個數n"); 48 Scanner reader = new Scanner(System.in); 49 int w=reader.nextInt();//背包的容量 50 int n=reader.nextInt();//物品的個數 51 Bag[] p=new Bag[n]; 52 //10 10 a 10 10 b 10 15 c 53 System.out.println("請依次輸入各個物品的重量w和價值v和名稱s"); 54 int weigth; 55 int value; 56 String pid; 57 for(int i=0;i<n;i++) 58 { 59 weigth=reader.nextInt(); 60 value=reader.nextInt(); 61 pid=reader.next(); 62 p[i]=new Bag(weigth,value,pid); 63 } 64 //System.out.println(z[1]+""+v[1]); 65 sort(p); 66 bq(p,0,w,0.0); 67 for(int i=0;i<n;i++) 68 { 69 System.out.println(p[i].wi+" "+p[i].pid); 70 } 71 72 } 73 74 } 75 76 class Bag 77 { 78 public int weight;//重量 79 public int value;//價值 80 public double wi;//權重 81 public String pid;//背包名稱 82 public Bag(int w,int v,String pid) 83 { 84 this.weight=w; 85 this.value=v; 86 this.pid=pid; 87 this.wi=(double)value/weight; 88 } 89 }
具體實現的問題大部分都在注釋中了,雖然也沒有多少注釋,還是講講吧。在控制台輸入的時候,要注意物品是先聲明,在使用對象屬性。最開始一直報錯,想了很久,都是用數組用習慣了,直接就使用數組元素了。排序算法用的是選擇,因為選擇排序對於元素較少的情況下計算效果還是比較理想的。貪心算法的主體用的是遞歸。算法的實現還是比較簡單的。主要是理解貪心算法的思想,做出每一步都是最優解的選擇。
