背包問題(01背包和完全背包)


  背包問題是一個經典的動態規划模型,容易描述,容易理解。背包問題可簡單描述為:給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內,我們如何選擇,才能使得物品的總價格最高。01背包問題的特點是,每種物品僅有一件,可以選擇放或不放。

01背包問題描述:

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

寫出狀態轉移方程:

  f[i][v]=max{f[i-1][v], f[i-1][v-c[i]]+w[i]}

f[i][v]:  前i件物品恰放入一個容量為v的背包可以獲得的最大價值

f[i-1][v]:  前i-1件物品……(同上),即不放入第i件物品的情況

f[i-1][v-c[i]]+w[i]:  放入第i件物品的情況,放入后的 f[i][v] 應該等於前 i-1 件物品在容量為 v-c[i] 上的最大價值加上 w[i]

空間優化:

  f[i][v]=max{f[i-1][v], f[i-1][v-c[i]]+w[i]}

  觀察黑色字體部分,發現二維數組完全可以用一維數組替代:

  f[v]=max{f[v], f[v-c[i]]+w[i]}

程序怎么寫?循環如何寫?

  首先考慮如果所有的物品都能放進去,那一定就是最大價值,如果只能放進去 i (i<N)件物品,那一定要選擇一個最優策略,這個策略的結果是價值最大,而每個 i 的最優策略實際上又是基於 i-1 的最優策略的。根據分析寫出如下循環

  for(i=0; i<N; ++i)

    for(v=V; v>w[i]; --v)  //逆序推能夠保證 f[v-c[i]] 保存的是狀態是 f[i-1][v-c[i]] ,也就是每個物品只被使用了一次;順序的話 f[v-c[i]] 保存的是 f[i][v-c[i]] ,每個物品有可能被使用多次,也就是完全背包問題的解法。

      f[v]=max(f[v], f[v-c[i]]+w[i])

poj上的3264題就是一道簡單的01背包問題,http://poj.org/problem?id=3624

我的代碼如下:

View Code
 1 #include <stdio.h>
 2 #define max(x, y) ((x)>(y) ? (x) : (y))
 3 int w[3403];
 4 int d[3403];
 5 int f[13000];
 6 int main()
 7 {
 8     int i, j, n, m;
 9     int nMax = 0;
10     scanf("%d %d", &n, &m);
11     for(i=0; i<n; ++i)
12     {
13         scanf("%d %d", &w[i], &d[i]);
14     }
15     for(i=0; i<n; ++i)
16     {
17         for(j=m; j>=w[i]; --j)
18         {
19             //printf("%d %d %d %d %d %d %d\n", __LINE__, j, i, f[j], w[i], d[i], f[j-w[i]]+d[i]);
20             f[j] = max(f[j], f[j-w[i]]+d[i]);
21         }
22     }
23     printf("%d\n", f[m]);
24     return 0;
25 }

poj上1384是一道完全背包問題,不過該問題求解的最小值,跟求最大值的最主要區別是小心初始化狀態數組http://poj.org/problem?id=1384

這里也給出代碼:

View Code
 1 #include <stdio.h>
 2 #define min(x, y) ((x)<(y) ? (x) : (y))
 3 #define MAX_INT 10000000  
 4 int p[501];
 5 int w[501];
 6 int f[10001];
 7 int main()
 8 {
 9     int t;
10     scanf("%d", &t);
11     while(t--)
12     {
13         int i, j, E, F, n, W;
14         for(i=0; i<10001; ++i)
15         {
16             f[i] = MAX_INT;//注意初始化
17         }
18         f[0] = 0; //注意初始化
19         scanf("%d %d", &E, &F);
20         scanf("%d", &n);
21         W = F-E;
22         for(i=0; i<n; ++i)
23         {
24             scanf("%d %d", &p[i], &w[i]);
25         }
26         for(i=0; i<n; ++i)
27         {
28             for(j=w[i]; j<=W; ++j)
29             {
30                 f[j] = min(f[j], f[j-w[i]] + p[i]);
31             }
32         }
33         if(f[W] != MAX_INT)
34         {
35             printf("The minimum amount of money in the piggy-bank is %d.\n", f[W]);
36         }
37         else
38         {
39             printf("This is impossible.\n");
40         }
41     } 
42     return 0;
43 }

 

 


免責聲明!

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



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