• 背包问题总结


    背包问题是一个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 }
  • 相关阅读:
    Android Studio快捷键
    Eclipse常用快捷键
    沉浸式状态栏
    JAVA起名规范
    c语言求数组长度
    自定义checkbox风格
    退出所有应用,监控打开了什么活动
    android权限大全
    广播接收者Receiver
    ImageView的常用属性
  • 原文地址:https://www.cnblogs.com/zzw1024/p/11930314.html
Copyright © 2020-2023  润新知