zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",dp[W]);
    }
    
    
    
     
  • 相关阅读:
    BZOJ4004: [JLOI2015]装备购买
    POJ3696:The Luckiest number
    BZOJ1053: [HAOI2007]反素数ant
    BZOJ1029: [JSOI2007]建筑抢修
    牛站(贪心+暴力做法)
    浅谈SPFA(没有特别的探讨,只是对某天晚上的思考做个记录)
    火车进栈问题(如何快速计算单个组合数)
    雷达设备
    畜栏预定
    防晒
  • 原文地址:https://www.cnblogs.com/orion7/p/7490916.html
Copyright © 2011-2022 走看看