DP查缺补漏之完全背包优化原理

DP查缺补漏之完全背包优化原理

先复习一下基本知识

  • 状态假设

    • DP[I][J]为前\(i\)个物品,容量小于\(j\)时的最优解(最大价值)
  • 状态转移

    • DP[I][J] = max(DP[I - 1][J], DP[I - 1][J - k*V[I]] + k*W[I])
      • 对于第\(i\)个物品,两种可能
        • 装入背包(装入\(1 \sim S_i(S_i * V[i] <= j)\)个)
    • 不装入背包
      • 则状态应通过前\(i - 1\)个物品,容量小于\(j\)时的最优解直接进行转移
  • 代码处理

    • for (int i = 1; i <= n; i++)
      {
      	for (int j = 1; j <= m; j++)
          {
      		for (int k = 0; k * v[i] <= j; k++)
              {
      			DP[i][j] = max(DP[i][j], DP[i - 1][j - v[i] * k] + w[i] * k);
              }
      	}
      }
      

优化思路(时间和空间)

  • 时间复杂度

    • 从状态方程分析

      • DP[I][J] = max(DP[I - 1][J], DP[I-1][J-V] + W, DP[I-1][J-2V] + 2W, ... , DP[I-1][J-NV] + NW)
      • DP[I][J-V] = MAX( DP[I-1][J-V], DP[I-1][J-2V] + 1W, ... , DP[I-1][J-NV] + (N-1)W)
        • 每一项都比DP[I][J]小一个W,最大值即DP[I][J-V]DP[I][J]相差一个W。
      • DP[I][J] = DP[I,J-V] + W
    • 用新转移方程实现

      • for (int i = 1; i <= n; i++)
        {
        	for (int j = 0; j <= m; j++)
            {
                DP[i][j] = DP[i - 1][j];
                if (j >= v[i])
                    DP[i][j] = max(DP[i][j], DP[i][j - v[i]] + w[i]);
            }
        }
        
      • 注意右边那项是DP[i][j - v[i]] + w[i],这与01背包不同

  • 空间复杂度

    • 从状态方程分析

      • DP[i][j] = max(DP[i][j], DP[i][j - v[i]] + w[i])
      • 仍然可以优化空间,但是与01不同的是这个方程并非滚动,本次的大答案只能由本次的小答案推出,所以第二层for应从小到大枚举
    • 代码实现

      • for (int i = 1; i <= n; i++)
        {
        	for (int j = v[i]; j <= m; j++)
            {
                 DP[j] = max(DP[j], DP[j - v[i]] + w[i]);
            }
        }
        
posted @ 2023-11-01 15:04  加固文明幻景  阅读(5)  评论(0编辑  收藏  举报