背包问题总结

背包问题是一个np问题:

一般题意为:

  存在n件物品,每件物品的重量为w[i],价值为v[i],现在有一个包,承重限制为weight,现在让你从n件物品中,选择一些物品装入背包中,在不超重的前提下,使得背包中所装物品的总价值最大。

  由于每件物品【应该是每种物品】存在着两种情况,一种是,每种物品唯有一件,这种情况称为0-1背包问题;

  另一种是,每种物品有无数件,这种情况称为完全背包问题。

  

  0-1背包问题:

   0-1背包问题存在两种情况,即,对于第i种物品,你只有选择或者不选择两种情况。

  (1)使用动态规划来解答:    

      考虑对第i件物品的选择策略,有两种策略:
      ①不放第i件物品,那么问题转化为前i-1件物品恰好装入容量为weight的背包中所能获得的最大价值,也即dp[i-1][weight]。【也就是整个背包重量用来装前i-1件物品】
      ②放第i件物品,那么问题转化为前i-1件物品恰好装入容量为weight-w[i]的背包中所能获得的最大价值,也即dp[i-1][weight-w[i]]+c[i]。【也就是前i-1件物品只能装到重量的v-w[i]】

      即选择物品和不选择物品这两种情况而已【weight为当前剩余的背包体积】

       状态转移方程:

        dp[i][u] = max{dp[i-1][u], dp[i-1][u-w[i]] + v[i]}  (1<=i<=n.   w[i]<=u<=weight)

      核心代码为:        

1 for(int i=1; i<n;++i) //从1开始,0为初始边界
2     for(int u=w[i];u<=weight;++v)//正序枚举u
3         dp[i][u] = max(dp[i-1][u], dp[i-1][u-w[i]] + c[i]);

      当然,为了缩小空间复杂度,我们也可以用一维数组求解,不过,u的遍历就要逆序遍历了   

      状态转移方程:

        dp[u] = max(dp[u], dp[u-w[i]]+v[i]);    1<=i<=n,  w[i]<=v<=weight

1 for(int i=0; i<=n; ++i)
2     for(int u=weight; u>=w[i]; --u)//逆序枚举
3         dp[u] = max(dp[u], dp[u-w[i]]+v[i]);

 

    (2)使用DFS来求解:

      很简单,即分两条路进行递归      

 1 void DFS(int index, int sumW, int sumV)
 2 {
 3     if(sumW>weight)    
 4         return;
 5     maxV = max(maxV, sumV);
 6     for(int i=index; i<n; ++i)
 7     {
 8         DFS(index+1, sumW, sumV);//不选择index
 9         DFS(index+1, sumW+w[index], sumV+v[index]);//选择index
10     }
11 }

  

  完全背包问题:

    (1)使用动态规划求解

      二维数组:

        状态转移方程:

        dp[i][u] = max{dp[i-1][u], dp[i][u-w[i]] + v[i]};     1<=i<=n,  w[i]<=u<=weight

        边界:

        dp[0][u] = 0  0<=v<=u

        

1 for(int i=1; i<n;++i) //从1开始,0为初始边界
2      for(int u=w[i];u<=weight;++v)//正序枚举u
3          dp[i][u] = max(dp[i-1][u], dp[i][u-w[i]] + c[i]);

 

      一维数组:

        状态转移方程:

        dp[u] = max{dp[u], dp[u-w[i]] + v[i]}    1<=i<=n,  w[i]<=u<=weight       

        边界:

        dp[u] = 0   0<=u<=weight

       

1 for(int i=1; i<=n; ++i)
2     for(int u=weight; u>=w[i]; --u)
3         dp[u] = max(dp[u], dp[u-w[i]]+v[i])

    

    使用DFS求解

    

 1 void DFS(int index, int sumV, int sumW)
 2 {
 3     if (sumW > weight)
 4         return;
 5     if (sumV> maxV)
 6         maxV = sumV;
 7     for (int i = index; i < n; ++i)
 8     {
 9         DFS(i + 1, sumV + v[index], sumW + w[index]); //选这件物品 然后继续选这一件 
10         DFS(i + 1, sumV + v[index], sumW + w[index]); //选这件物品 然后选下一件 
11         DFS(i + 1, sumV, sumW); //不选这件物品 
12     }
13 }

 

posted @ 2019-11-25 20:36  自由之翼Az  阅读(329)  评论(0编辑  收藏  举报