动态规划(0-1背包)

0-1背包

  有一个容量为N的背包,要用这个背包装下的物品价值最大,这些物品有两个属性,体积w和价值v。

  定义一个二维数组dp[i] [j],表示前i件物品体积不超过j的最大价值,第i件物品的体积为w,价值为v,根据第i件物品是否添加到背包中,可以分两种情况进行讨论。

  • 第i件物品没有添加到背包,总体积不超过j的前i件物品的最大价值就是总体积不超过j的前i-1件物品的总价值,dp[i] [j]=dp[i-1] [j]
  • 第i件物品添加到背包中,dp[i] [j]=dp[i-1] [j-w]+v

  第i件物品可以添加也可以不添加,取决于哪种情况下最大价值更大。因此状态转移方程为:

  dp[i] [j]=max(dp[i-1] [j],dp[i-1] [j-w]+v)

代码:

public int knapsack(int W,int N,int []weights,int []values){
    int [][]dp=new int[N+1][W+1];
    for(int i=1;i<=N;i++){
        int w=weights[i-1];
        int v=values[i-1]; //第i个物品的体积和价值
        for(int j=1;j<=W;j++){
            if(j>=w)
                dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-w]+v);
            else
                dp[i][j]=dp[i-1][j];
        }
    }
    return dp[N][W];
}

空间优化

  在程序实现时可以对0-1背包进行优化。观察状态转移方程就可以知道,前i件物品的状态仅与前i-1件物品的转态有关,因此可以将dp定义为一维数组,其中dp[j]既可以表示dp[i-1] [j],也可以表示dp[i] [j]。此时

dp[j]=max(dp[j],dp[j-w]+v)

代码:

public int knapsack(int W,int N,int[]weights,int[]values){
    int []dp=new int[W+1];
    for(int i=1;i<=N;i++){
        int w=weights[i-1];
        int v=values[i-1];
        for(int j=W;j>=1;j--){
            if(j>=w)
                dp[j]=Math.max(dp[j],dp[j-w]+v);
        }
    }
    return dp[W];
}
原文地址:https://www.cnblogs.com/yjxyy/p/11119240.html