DP 01背包问题

  01 背包问题

  有n个重量和价值分别为wi和vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中总价值总和的最大值。

 

  这是被称为背包问题的一个著名的问题。01 背包是背包问题的其中一种,对于任意一个物品,可以选择0个(不选)和1个。

 dp[i+1][j]表示从0到i这i+1个物品中选出总重量不超过j的物品时总价值的最大值。
我们可以得出如下的递推关系式

   首先 dp[0][j]=0
    dp[i+1][j]=dp[i][j]  (j<w[i])
    dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i])  (其他)
void solve()
{
    for(int i=0;i<n;i++)
        for(int j=0;j<=W;j++)
        {
            if(j<W[i])
                dp[i+1][j]=dp[i][j];
            else
                dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);
        }
    printf("%d\n",dp[n][W]);
}

其实我们还可以讲两个数组滚动使用来实现重复使用。例如

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

这一递推式中,dp[i+1]计算时只需要dp[i]和dp[i+1],所以可以结合奇偶性写成如下形式:

int dp[2][maxw];
void solve()
{
    for(int i=0;i<n;i++)
        for(int j=0;j<=W;j++)
        {
            if(j<w[i])
                dp[(i+1)&1][j]=dp[i&1][j];
            else
                dp[(i+1)&1][j]=max(dp[i&1][j],dp[(i+1)&1][j-w[i]]+v[i]);
        }
    printf("%d\n",dp[n&1][W]);
}
当n很大时,就可以节省很多空间。

还可以这么写,只用一维数组,不过我觉得没上面那个好理解,不具有通适性。
void solve()
{
        for(int i=0;i<n;i++)
            for(int j=W;j>=w[i];j--)
            {
                dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
            }
    printf("%d\n",dp[W]);
}

 

 
posted @ 2017-09-07 17:37  Zireael  阅读(317)  评论(0编辑  收藏  举报