算法设计与分析-0/1背包问题(动态规划分析)

0/1背包问题

1.分析最优解的结构

​ 0/1背包问题可以形式化表述为一个整数规划问题:
m a x ∑ i = 1 n v i x i       { ∑ i = 1 n w i x i ≤ c x i ∈ { 0 , 1 } 1 ≤ i ≤ n max\sum_{i=1}^n{v_ix_i} \ \ \ \ \ \begin{cases} \sum_{i=1}^n{w_ix_i}\leq c \\ x_i \in \{0,1\} & 1\leq i \leq n \end{cases} maxi=1nvixi     {i=1nwixicxi{0,1}1in
​ 问题的解为一个n元0-1向量, ( x 1 , x 2 , x 3 , . . . , x n ) ,   x i ∈ { 0 , 1 }   ( 1 ≤ i ≤ n ) (x_1,x_2,x_3,...,x_n),\ x_i \in \{0,1\} \ (1 \leq i \leq n) (x1,x2,x3,...,xn), xi{0,1} (1in)。0/1背包问题具有最优子结构性质,因此可以使用动态规划方法解决。最优子结构性质证明如下:

​ 首先假设原问题的一个最优解为 ( x 1 , x 2 , x 3 , . . . , x n ) (x_1,x_2,x_3,...,x_n) (x1,x2,x3,...,xn),考虑0/1背包的一个子问题为:
m a x ∑ i = 1 n − 1 v i x i       { ∑ i = 1 n − 1 w i x i ≤ c − w n x n x i ∈ { 0 , 1 } 1 ≤ i ≤ n − 1 max\sum_{i=1}^{n-1}{v_ix_i} \ \ \ \ \ \begin{cases}\sum_{i=1}^{n-1}{w_ix_i}\leq c-w_nx_n\\x_i \in \{0,1\} & 1\leq i \leq n-1\end{cases} maxi=1n1vixi     {i=1n1wixicwnxnxi{0,1}1in1
​ 则相应的子问题的最优解应该为 ( x 1 , x 2 , x 3 , . . . , x n − 1 ) (x_1,x_2,x_3,...,x_{n-1}) (x1,x2,x3,...,xn1)。假设存在一个解 ( x 1 ′ , x 2 ′ , x 3 ′ , . . . , x n − 1 ′ ) (x'_1,x'_2,x'_3,...,x'_{n-1}) (x1,x2,x3,...,xn1),使 ∑ i = 1 n − 1 v i x i ′ > ∑ i = 1 n − 1 v i x i \sum_{i=1}^{n-1}{v_ix'_i}>\sum_{i=1}^{n-1}{v_ix_i} i=1n1vixi>i=1n1vixi,由于 ∑ i = 1 n − 1 w i x i ≤ c − w n x n \sum_{i=1}^{n-1}{w_ix_i}\leq c-w_nx_n i=1n1wixicwnxn,可得 ∑ i = 1 n − 1 w i x i + w n x n ≤ c \sum_{i=1}^{n-1}{w_ix_i}+w_nx_n\leq c i=1n1wixi+wnxnc,即存在一个n元0-1向量 ( x 1 ′ , x 2 ′ , x 3 ′ , . . . , x n − 1 ′ , x n ) (x'_1,x'_2,x'_3,...,x'_{n-1},x_n) (x1,x2,x3,...,xn1,xn)是原问题的一个可行解。可以得到:
∑ i = 1 n − 1 v i x i ′ + v i x n > ∑ i = 1 n − 1 v i x i + v i x n = ∑ i = 1 n v i x i \sum_{i=1}^{n-1}{v_ix'_i}+v_ix_n>\sum_{i=1}^{n-1}{v_ix_i}+v_ix_n=\sum_{i=1}^n{v_ix_i} i=1n1vixi+vixn>i=1n1vixi+vixn=i=1nvixi
​ 即这个可行解计算的结果比原问题的最优解要大,这产生了矛盾。因此可以证明0/1背包问题具有最优子结构性质。

2.建立递归关系

​ 设0/1背包问题的子问题为:
m a x ∑ k = 1 i v k x k       { ∑ k = 1 i w k x k ≤ j x k ∈ { 0 , 1 } 1 ≤ k ≤ i max\sum_{k=1}^i{v_kx_k} \ \ \ \ \ \begin{cases} \sum_{k=1}^i{w_kx_k}\leq j \\ x_k \in \{0,1\} & 1\leq k \leq i \end{cases} maxk=1ivkxk     {k=1iwkxkjxk{0,1}1ki
​ 最优解用m(i,j)表示,i表示可选物品1-i,j表示容量为j。根据0/1背包的最优子结构性质,可以得到计算m(i,j)的递归式如下:
i = 1      m ( i , j ) = { 0 0 ≤ j < w i v i w i ≤ j i > 1      m ( i , j ) = { m ( i − 1 , j ) 0 ≤ j < w i m a x { m ( i − 1 , j ) ,   m ( i − 1 , j − w i ) + v i } w i ≤ j i = 1 \ \ \ \ m(i,j)= \begin{cases} 0 & 0\leq j<w_i \\ v_i & w_i \leq j \end{cases} \\ i>1 \ \ \ \ m(i,j)= \begin{cases} m(i-1,j) & 0\leq j < w_i \\ max\{m{(i-1,j), \ m(i-1,j-w_i)+v_i}\} & w_i \leq j \end{cases} i=1    m(i,j)={0vi0j<wiwiji>1    m(i,j)={m(i1,j)max{m(i1,j), m(i1,jwi)+vi}0j<wiwij

3.计算最优值

​ 根据以上构造的递推关系,进行最优值的计算。

int solution(int m[][c+1],int weight[],int value[],int c,int n){			
    //初始化,当j>=weight[0],m[0][j]=value[0]
    memset(dp,0,sizeof(dp));
    for(int j=weight[0];j<=c;j++) m[0][j]=value[0];
    for(int i=1;i<n;i++){
        for(int j=0;j<=c;j++){
            if(j<weight[i]) m[i][j]=m[i-1][j];
            else m[i][j]=max(m[i-1][j],m[i-1][j-weight[i]]+value[i]);
        }
    }
    return m[n-1][c];
}

​ 主要的计算量为m[i][j]的计算,因此该算法的时间复杂度为 O ( c n ) O(cn) O(cn)

4.构造最优解

​ 根据m[i][j]中记录的信息判断最优解是从哪个子问题产生的,得到结果的0-1向量:

void traceback(int m[][c+1], int weight[] ,int n, int c, int x[]){
    for(int i=1;i<n;i++){
        if(m[i][c]==m[i-1][c]) x[i] = 0;
        else{
            x[i] = c;
            c -= weight[i];
        }
    }
    x[0] = m[0][c]?1:0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值