1. 程式人生 > >[C++] 貪心算法之活動安排、背包問題

[C++] 貪心算法之活動安排、背包問題

基本思想 nbsp 考慮問題 最終 jpg 實例 使用 n) 最好的

一、貪心算法的基本思想

  在求解過程中,依據某種貪心標準,從問題的初始狀態出發,直接去求每一步的最優解,通過若幹次的貪心選擇,最終得出整個問題的最優解。

  從貪心算法的定義可以看出,貪心算法不是從整體上考慮問題,它所做出的選擇只是在某種意義上的局部最優解,而由問題自身的特性決定了該題運用貪心算法可以得到最優解。如果一個問題可以同時用幾種方法解決,貪心算法應該是最好的選擇之一。

二、貪心算法的基本要素

  (1)最優子結構性質

  (2)貪心選擇性質(局部最優選擇)

三、貪心算法實例

  1、活動安排

  設有n個活動的集合 E = {1,2,…,n},其中每個活動都要求使用同一資源,如演講會場等,而在同一時間內只有一個活動能使用這一資源。

  每個活動 i 都有一個要求使用該資源的起始時間 si 和一個結束時間 fi,且 si < fi。如果選擇了活動i,則它在半開時間區間 [si ,fi ) 內占用資源。若區間 [si , fi )與區間 [sj, fj ) 不相交,則稱活動i與活動j是相容的。當 si ≥ fj 或 sj ≥ fi 時,活動 i 與活動 j 相容。

  活動安排問題就是在所給的活動集合中選出最大的相容活動子集合。

  例如:

技術分享

 1 #include <iostream>   
 2 using namespace std;   
 3   
 4 #define NUM 50 
 5 
 6 void
GreedySelector(int n, int s[], int f[], bool b[]) 7 { 8 b[1]=true; //默認將第一個活動先安排 9 int j=1; //記錄最近一次加入b中的活動 10 11 //依次檢查活動i是否與當前已選擇的活動相容 12 for(int i=2;i<=n;i++) 13 { 14 if (s[i]>=f[j]) 15 { 16 b[i]=true; 17 j=i;
18 } 19 else 20 b[i]=false; 21 } 22 } 23 24 int main() 25 { 26 int s[] = {0,1,3,0,5,3,5,6,8,8,2,12}; //存儲活動開始時間 27 int f[] = {0,4,5,6,7,8,9,10,11,12,13,14}; //存儲活動結束時間 28 bool b[NUM]; //存儲被安排的活動編號 29 int n = (sizeof(s) / sizeof(s[0])) - 1; 30 31 GreedySelector(n, s, f, b); 32 33 for(int i = 1; i <= n; i++) //輸出被安排的活動編號和它的開始時間和結束時間 34 { 35 if(b[i]) cout << "活動 " << i << " :" << "(" << s[i] << "," << f[i] << ")" <<endl; 36 } 37 return 0; 38 }

  2、背包問題

  給定一個載重量為 M 的背包,考慮 n 個物品,其中第 i 個物品的重量 wi(1 ≤ i ≤ n),價值 vi(1 ≤ i ≤ n),要求把物品裝滿背包,且使背包內的物品價值最大。
  有兩類背包問題(根據物品是否可以分割),如果物品不可以分割,稱為 0—1 背包問題(動態規劃);如果物品可以分割,則稱為背包問題(貪心算法)。

  例如:

  有3種方法來選取物品:

    (1)當作 0—1 背包問題,用動態規劃算法,獲得最優值 220;
    (2)當作 0—1 背包問題,用貪心算法,按性價比從高到底順序選取物品,獲得最優值 160。由於物品不可分割,剩下的空間白白浪費。
    (3)當作背包問題,用貪心算法,按性價比從高到底的順序選取物品,獲得最優值 240。由於物品可以分割,剩下的空間裝入物品 3 的一部分,而獲得了更好的性能。

技術分享

圖2.1 背包問題

 1 #include <iostream>   
 2 using namespace std;   
 3   
 4 #define NUM 50
 5 
 6 //這裏假設 w[], v[] 已按要求排好序 
 7 void Knapsack(int n,float M,float v[],float w[],float x[])  
 8 {
 9     int i; 
10     for(i = 1; i <= n; i++) x[i] = 0;    //初始化數組 
11     float c  =  M;  
12     for(i = 1;i <= n; i++)                //全部被裝下的物品,且將 x[i] = 1  
13     {  
14         if(w[i]>c) break;
15         x[i] = 1;  
16         c -= w[i];  
17     }  
18   
19     if(i <= n) x[i] = c / w[i];  //將物品i 的部分裝下
20 } 
21 
22 int main()  
23 {
24     float M = 50;                //背包所能容納的重量  
25     float w[] = {0,10,20,30};   //這裏給定的物品按價值降序排序 
26     float v[] = {0,60,100,120};  
27       float x[NUM];                //存儲每個物品裝入背包的比例 
28       
29     int n = (sizeof(w) / sizeof(w[0])) - 1; 
30       
31     Knapsack(n, M, v, w, x);
32      
33     for(int i = 1; i <= n; i++)
34         cout << "物品 " << i << " 裝入的比例: " << x[i] << endl;  
35     return 0;  
36 }

[C++] 貪心算法之活動安排、背包問題