背包

背包

你是喜欢一级包,二级包还是三级包呢?
当然是01包了

01背包

先来看一个问题:

你有一个可以容纳m的背包,然后你有n个零食,每个零食有自己的重量w[i],每个零食还有自己的好吃度v[i],作为吃货的你当然是希望你的背包里面装的零食的好吃度越高越好了,但是呢,你的背包可能不够大,所以你需要对n个零食进行选择(当然你也可以选择换一个更大的背包,但是XXX说能用钱解决的都不算问题,所以这个就暂时不考虑了)。

那么你怎么选择这些零食呢?
贪心?当然可以,这里不多叙述……
我今天要说的重点当然是dp了,毕竟动态规划还是那么优秀,但是这个的复杂度好像也有点高啊。
说到动态规划就不得不说一个动态转移方程。
动态规划的核心就在于动态转移方程。
先说这个01背包,对于你怎么选择一个零食,不外乎就两种选法,选或者不选。
那最先想到的肯定也是暴力啊,把所有情况都想一下,然后比较哪种比较好,dp的01背包也就是这种想法吧。
首先你需要一个数组dp,dp[j]表示容量为j的背包最多能有多少好吃度。

那么我们最后要得到的答案是dp[m],因为背包的最大容量为m,那么我们是不是可以这样考虑:

对于每一个零食我们进行判断,将这个零食取不取两种情况都考虑一下。 那么我们对于零食w[i]进行一下考虑:

dp[j]就表示不取,dp[j-w[i]]+v[i]就表示取(为什么是这样的呢?我们之前说了dp[j]表示容量为j的背包最多能有多少好吃度,那么如果你现在取w[i],那么背包的容量是不是只有j-w[i]了呢?但是这个时候你背包里面的好吃度就变成了dp[j-w[i]]+v[i](v[i]表示w[i]的好吃度))所以你需要更新一下dp[j],因为我们要确保dp[j]是背包容量为j的时候的最优解,即当背包容量为j的时候,dp[j]就是最大的好吃度,那么转移方程就变成了
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
现在已经知道了转移方程,那么是不是可以通过对每个w[i]进行判断,进行选择,取还是不取,来确定最优的dp[j]呢?
这就需要两个循环了

for(int i=1;i<=n;i++){   //对每个w[i]的判断
    for(int j=m;j>=w[i];j--){   //对背包容量为j的时候的好吃度的更新,得到最优的dp[j]
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);  //更新dp[j],得到最优的解
    }
}

说白了01背包其实还是一个暴力,对于每种情况都进行了考虑,所以它的复杂度达到了O(mn)
如果你看懂了,你就可以去练练手了:
poj 3624
来一份AC的代码吧

#include <iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
int w[35000],v[35000],dp[35000];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d",&w[i],&v[i]);
        for(int i=1;i<=n;i++){
            for(int j=m;j>=w[i];j--){
                dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
            }
        }
        printf("%d\n",dp[m]);
    }
    return 0;
}
posted @ 2018-12-06 12:20  凌乱风中  阅读(130)  评论(0编辑  收藏  举报