貪心算法求解背包問題


一.貪心算法

  1.貪心算法概念

  貪婪算法(Greedy algorithm)是一種對某些求最優解問題的更簡單、更迅速的設計技術。用貪婪法設計算法的特點是一步一步地進行,常以當前情況為基礎根據某個優化測度作最優選擇,而不考慮各種可能的整體情況,它省去了為找最優解要窮盡所有可能而必須耗費的大量時間,它采用自頂向下,以迭代的方法做出相繼的貪心選擇,每做一次貪心選擇就將所求問題簡化為一個規模更小的子問題,通過每一步貪心選擇,可得到問題的一個最優解,雖然每一步上都要保證能獲得局部最優解,但由此產生的全局解有時不一定是最優的,所以貪婪法不要回溯。

  貪婪算法是一種改進了的分級處理方法。其核心是根據題意選取一種量度標准。然后將這多個輸入排成這種量度標准所要求的順序,按這種順序一次輸入一個量。如果這個輸入和當前已構成在這種量度意義下的部分最佳解加在一起不能產生一個可行解,則不把此輸入加到這部分解中。這種能夠得到某種量度意義下最優解的分級處理方法稱為貪婪算法。

  2.貪心算法求解思路

  基本思路①建立數學模型來描述問題。②把求解的問題分成若干個子問題。③對每一子問題求解,得到子問題的局部最優解。④把子問題的解局部最優解合成原來解問題的一個解。

  實現該算法的過程:從問題的某一初始解出發;while 能朝給定總目標前進一步 do;求出可行解的一個解元素;由所有解元素組合成問題的一個可行解。

  3.利用貪婪策略,需要解決的兩個問題

 

  確定問題是否能用貪心策略求解;一般來說,適用於貪心策略求解的問題具有以下特點:貪心選擇性質和最優子結構性質。
  ① 貪心選擇性質:可通過局部的貪心選擇來達到問題的全局最優解。運用貪心策略解題,一般來說需要一步步的進行多次的貪心選擇。在經過一次貪心選擇之后,原問題將變成一個相似的,但規模更小的問題,而后的每一步都是當前看似最佳的選擇,且每一個選擇都僅做一次。
  ② 最優子結構性質:原問題的最優解包含子問題的最優解,即問題具有最優子結構的性質。在背包問題中,第一次選擇單位質量最大的貨物,它是第一個子問題的最優解,第二次選擇剩下的貨物中單位重量價值最大的貨物,同樣是第二個子問題的最優解,依次類推。

 

二.背包問題

  背包問題(Knapsack problem)是一種組合優化的NP完全問題。問題可以描述為:給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內,我們如何選擇,才能使得物品的總價格最高。問題的名稱來源於如何選擇最合適的物品放置於給定背包中。相似問題經常出現在商業、組合數學,計算復雜性理論、密碼學和應用數學等領域中。也可以將背包問題描述為決定性問題,即在總重量不超過W的前提下,總價值是否能達到V?它是在1978年由Merkel和Hellman提出的。

  題目有N件物品和一個容量為V的背包。第i件物品的重量是w[i],價值是v[i]。求解將哪些物品裝入背包可使這些物品的重量總和不超過背包容量,且價值總和最大。

 三.貪心算法求解背包問題

 1 import java.util.Arrays;
 2 
 3 /**
 4  * 貪心算法--->背包問題
 5  * 假設有一個背包最大可以裝    150kg 物品
 6  * 某物品    重量        價值(元)      性價比(單位重量的價格)    
 7  *   a  35kg     10              10/35
 8  *   b  30kg     40              40/30
 9  *   c  60kg     30           30/60
10  *   d  50kg     50           50/50
11  *   e  40kg     35           35/40
12  *   f  10kg     40           40/10
13  *   g  25kg     30           30/25
14  *   
15  * 求:背包可以裝入的最大價值?
16  * @author Administrator
17  *
18  */
19 public class Knapsack {
20     /**
21      * 背包最大容量
22      */
23     private static  int KNAPSACK_MAX_CAPACITY=150;
24     /**
25      * 保存各個物品的重量
26      */
27     private static int [] goods_weights=new int [] {35,30,60,50,40,10,25};
28     /**
29      * 保存各個物品的價值
30      */
31     private static int [] goods_values=new int[] {10,40,30,50,35,40,30};
32     
33     /**
34      * 貪婪算法實現背包問題求解
35      * @param capacity  背包容量
36      * @param weights   各個物品的重量
37      * @param values    各個物品的價值
38      */
39     private void knapsackGreedy(int capacity,int weights[],int values[]) {
40         int n=weights.length;   //物品的數量
41         
42         Double[] r=new Double[n];  //保存性價比的數組
43         int [] index=new int[n]; //保存按性價比排序的物品的下標
44         //計算得到各個物品的性價比
45         for (int i = 0; i < n; i++) {
46             r[i]=(double)values[i]/weights[i];
47             index[i]=i;  //初始化各個物品的默認性價比排序
48         }
49         
50         //對各個物品的性價比進行排序
51         for(int i=0;i<r.length-1;i++) {
52             for(int j=i+1;j<r.length;j++) {
53                 if(r[i]<r[j]) {
54                     double temp=r[i];
55                     r[i]=r[j];
56                     r[j]=temp;
57                     
58                     //將排序后性價比的下標更新為性價比排序后的位置
59                     int x=index[i];
60                     index[i]=index[j];
61                     index[j]=x;
62                 }
63             }
64         }
65         
66         //將排序好的重量和價值分別保存到數組
67         int [] w1=new int[n];
68         int [] v1=new int[n];
69         for(int i=0;i<n;i++) {
70             w1[i]=weights[index[i]];
71             v1[i]=values[index[i]];
72         }
73         
74         //將物品裝入背包
75         //記錄哪些物品已經被裝入背包       0 沒有裝入背包    1 代表已經裝入背包
76         int [] x=new int[n];  
77         int maxValue=0;
78         for(int i=0;i<n;i++) {
79             if(w1[i]<=capacity) {
80                 //還可以裝的下
81                 x[i]=1;  //表示將該物品裝入背包
82                 System.out.println("物品:"+w1[i]+" 被放進了");
83                 maxValue+=v1[i];
84                 capacity-=w1[i];
85             }
86         }
87         System.out.println("總共放下的物品的數量為:"+Arrays.toString(x));
88         System.out.println("最大價值為:"+maxValue);
89     }
90     
91     
92     public static void main(String[] args) {
93         Knapsack k=new Knapsack();
94         k.knapsackGreedy(KNAPSACK_MAX_CAPACITY, goods_weights,
95                 goods_values);
96     }
97 }

 四.測試結果

物品:10 被放進了
物品:30 被放進了
物品:25 被放進了
物品:50 被放進了
物品:35 被放進了
總共放下的物品的數量為:[1, 1, 1, 1, 0, 0, 1]
最大價值為:170


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM