[学习笔记]0-1背包问题

时间:2022-02-23 18:42:27

0-1背包问题

给定n个物品和一个背包。其中物品i的重量为wi,价值为vi,背包容量为c。

问该如何选择放入背包的物品,使得背包中物品价值总和最大?

 

分析

问题等价与求集合{x1,x2,...,xn},其中xi {0,1}。使得:

Σxiwi <= c  && maxΣvixi

因此可想到递归式

if (w1<=j):

  max(1,j) = v1

else:

  max(1,j) = 0

if (wi<=j):

  max(i,j) = max{max(i-1,j), max(i-1,j-wi)+vi}

else:

  max(i,j) = max(i-1,j)

(其中max(i,j)表示背包容量为j,可选物品为1,2,...,i)

 

然后就有以下算法

 

 1 #define MAX(a,b) a>b?a:b
 2 
 3 int backpack(int w[], int v[], int n, int c)
 4 {
 5     int max[n+1][c+1];
 6     for (int j = 0; j <= c; j++) 
 7     {
 8         if (j<w[1]) max[1][j] = 0;
 9         else max[1][j] = w[1];
10     }
11     for (int i = 2; i <= n; i++) 
12     {
13         for (int j = 0; j <= c; j++)
14         {
15             if (j < w[i]) max[i][j] = max[i-1][j];
16             else max[i][j] = MAX(max[i-1][j], max[i-1][j-w[i]]+v[i]);
17         }
18     }
19     return max[n][c];
20 }

 

但是上述方法只是返回了最大价值,要想构造最优解,可以将backpack函数改为返回max数组,然后利用下述函数构造:

 1 int* OptimalSolution(int **m, int w[], int n, int c)
 2 {
 3     int x[n+1];
 4     for (int i = n; i > 1; i--)
 5     {
 6         if (max[i][c]==max[i-1][c]) x[i] = 0;
 7         else
 8         {
 9             x[i] = 1;
10             c-=w[i];
11         }
12     }
13     x[1] = max[1][c]?1:0;
14     return x;
15 }

 

 

优化

(书中有一个优化的算法,暂时不想看。。过两天看看。)