0-1背包问题


背包问题是一种求最优解的问题,我们可以使用动态规划(DP)和回溯法来解决这类问题


参考文献:

[1] 最通俗易懂的01背包问题讲解


动态规划

动态规划Dynamic programmingDP)是一种在数学计算机科学经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题最优子结构性质的问题。

动态规划在查找有很多重叠子问题的情况的最优解时有效。它将问题重新组合成子问题。为了避免多次解决这些子问题,它们的结果都逐渐被计算并被保存,从简单的问题直到整个问题都被解决。因此,动态规划保存递归时的结果,因而不会在解决同样的问题时花费时间。

动态规划只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。

问题描述:

有一个能装12kg(capacity)的背包,准备买6件(typeTotal)物品,各自的重量(kg)和价值分别为:

0     0

1     2

3     5

2     3

6     10

2      4

对于一件物品,只存在装(1)和 不装(0)两种状态,不能装一部分或者一件物品拿走多次,求问他能拿走的最高价值是多少?

问题分析:

f[i,j]表示在前i0\leq i\leq typeTotal)个物品中能够装入容量为j0\leq j\leq capacity)的背包的物品的最大价值,则可以得到如下的动态规划函数:

f[i,j] = 0 \left ( i == 0 || j == 0\right )

f[i,j] = f[i-1,j],j < weight[i] ①

f[i,j] = max\left \{ f[i-1,j], f[i-1,j-weight[i]]+Val[i] \right \} , j>weight[i] ②  ②

式表明:如果第i个物品的重量大于背包的容量,则装人前i个物品得到的最大价值和装入前i-1个物品得到的最大价是相同的,即物品i不能装入背包; 

式表明:如果第i个物品的重量小于背包的容量,则会有一下两种情况:  

  • 如果把第i个物品装入背包,则背包物品的价值等于第i-1个物品装入容量位j-wi的背包中的价值加上第i个物品的价值vi;;
  • 如果第i个物品没有装入背包,则背包中物品价值就等于把前i-1个物品装入容量为j的背包中所取得的价值。显然,取二者中价值最大的作为把前i个物品装入容量为j的背包中的最优解。

C代码实现:

#include "stdio.h"
#include "stdlib.h"

/* 0-1 背包问题 */
#define len 100
int main()
{
    int capacity;
    int optimumSol[len+1][len+1];
    int weight[len];
    int val[len];
    int typeTotal;
    scanf("%d %d", &capacity, &typeTotal);
    for (int i = 1; i <= typeTotal; i++) {
        scanf("%d %d", &weight[i], &val[i]);
    }
    memset(optimumSol, 0, sizeof(optimumSol)/sizeof(int));
    int i, j;
    for (i = 1; i <= typeTotal; i++) {
        for (j = 0; j <= capacity; j++) {
            if (j < weight[i]) {
                //由i-1 >= 0 => i >= 1
                optimumSol[i][j] = optimumSol[i-1][j];
            } else {
                optimumSol[i][j] = optimumSol[i-1][j] > optimumSol[i-1][j-weight[i]] + val[i] ? 
                optimumSol[i-1][j] : optimumSol[i-1][j-weight[i]] + val[i];
            }
            printf("%d--%d--%d\n", i, j, optimumSol[i][j]);
        }
        
    }
    printf("optimumSol = %d\n", optimumSol[typeTotal][capacity]);

    return 0;
}

è¿éåå¾çæè¿°

ubuntu@VM-0-4-ubuntu:~/codeForTest$ ./ans 
12 6 
0 0
1 2
3 5
2 3
6 10
2 4
1--0--0
1--1--0
1--2--0
1--3--0
1--4--0
1--5--0
1--6--0
1--7--0
1--8--0
1--9--0
1--10--0
1--11--0
1--12--0
2--0--0
2--1--2
2--2--2
2--3--2
2--4--2
2--5--2
2--6--2
2--7--2
2--8--2
2--9--2
2--10--2
2--11--2
2--12--2
3--0--0
3--1--2
3--2--2
3--3--5
3--4--7
3--5--7
3--6--7
3--7--7
3--8--7
3--9--7
3--10--7
3--11--7
3--12--7
4--0--0
4--1--2
4--2--3
4--3--5
4--4--7
4--5--8
4--6--10
4--7--10
4--8--10
4--9--10
4--10--10
4--11--10
4--12--10
5--0--0
5--1--2
5--2--3
5--3--5
5--4--7
5--5--8
5--6--10
5--7--12
5--8--13
5--9--15
5--10--17
5--11--18
5--12--20
6--0--0
6--1--2
6--2--4
6--3--6
6--4--7
6--5--9
6--6--11
6--7--12
6--8--14
6--9--16
6--10--17
6--11--19
6--12--21

运行结果ok。


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值