01背包问题-基本实现

来源:互联网 发布:淘宝汽车用品店排名 编辑:程序博客网 时间:2024/06/04 19:47
0-1背包问题定义 & 基本实现

问题:有个容量为V大小的背包,有很多不同重量weight[i](i=1..n)不同价值value[i](i=1..n)的物品,每种物品只有一个,想计算一下最多能放多少价值的货物。

DP的关键也是难点是找到最优子结构和重叠子问题,进而找到状态转移方程,编码就相对容易些。最优子结构保证每个状态是最优的,重叠子问题也即n状态的求法和n-1状态的求法是一样的;DP在实现上一般是根据状态转移方程自底向上的迭代求得最优解(也可以使用递归自顶向下求解)。

回到0-1背包,每个物体i,对应着两种状态:放入&不放入背包。背包的最优解是在面对每个物体时选择能够最大化背包价值的状态。0-1背包的状态转移方程为

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

f(i,v)表示前i个物体面对容量为v时背包的最大价值,c[i]代表物体i的cost(即重量),w[i]代表物体i的价值;如果第i个物体不放入背包,则背包的最大价值等于前i-1个物体面对容量v的最大价值;如果第i个物体选择放入,则背包的最大价值等于前i-1个物体面对容量v-cost[i]的最大价值加上物体i的价值w[i]。

对于实现,一般采用一个二维数组(状态转移矩阵)dp[i][j]来记录各个子问题的最优状态,其中dp[i][j]表示前i个物体面对容量j背包的最大价值。

下面给出0-1背包的基本实现,时间复杂度为O(N*V),空间复杂度也为O(N*V),初始化的合法状态很重要,对于第一个物体即f[0][j],如果容量j小于第一个物体(编号为0)的重量,则背包的最大价值为0,如果容量j大于第一个物体的重量,则背包最大价值便为该物体的价值。为了能单步验证每个状态的最优解,程序最后将状态转移矩阵的有效部分输出到了文件。

代码如下:
#includeusing namespace std;  int maxValue[11][201];int weight[11];int value[11];int V, N; void main(){    int i, j;    scanf("%d %d",&V,&N);    for(i = 0; i < N;++i)    {       scanf("%d%d",&weight[i],&value[i]);    }    for(i = 0; i < N;++i)    {       for(j = 0; j <= V; ++j)       {           if(i >0)           {              maxValue[i][j] =maxValue[i-1][j];              if(j >= weight[i])              {                 int tmp = maxValue[i-1][j-weight[i]] +value[i];                 maxValue[i][j] = ( tmp > maxValue[i][j]) ?tmp : maxValue[i][j];              }           }else            {              if(j >= weight[0])                 maxValue[0][j] = value[0];           }       }    }    printf("%d",maxValue[N-1][V]);       freopen("C:\\dp.txt","w",stdout);    for(i = 0; i <= N;++i)    {       for(j = 0; j <= V; ++j)       {           printf("%d  ",maxValue[i][j]);       }       printf("\n");    } }


测试用例:

1
2
3
4
5
6
7
10 3
 
3 4
 
4 6
 
5 7
程序输出的状态转移矩阵如下图,第一行表示第1个物体对于容量0至V时的最优解,即背包最大价值。该实现方法是0-1背包最基本的思想,追踪状态转移矩阵有助于加深理解,POJ上单纯的0-1背包题目也有不少,如3624等,可以水一下,加深理解。

0 0
原创粉丝点击