• DP


    完全背包问题

    有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。

    第 i 种物品的体积是 vi,价值是 wi。

    求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
    输出最大价值。

    输入格式
    第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

    接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。

    输出格式
    输出一个整数,表示最大价值。

    数据范围
    0<N,V≤1000
    0<vi,wi≤1000
    输入样例
    4 5
    1 2
    2 4
    3 4
    4 5
    输出样例:
    10

    学习完全背包时一定要先学会01背包,01背包传送门
    DP - 背包九讲之01背包

    问题大意:

    完全背包问题和01背包问题很相似,给出n个物品和容量为m的背包,每件物品都有他的体积和价值,每件物品可以拿0次和无限次,询问背包内可以容纳的最大价值是多少。

    问题分析:

    我们知道在01背包中:每件物品只有拿和不拿两种选择,但是在完全背包中,每件物品可以拿最多无数次,这样要怎么把状态表示出来呢,如果按照01背包的思路,我们在第二重循环中只要枚举要几个就可以了,一直到容积的最大值,贴代码(错误代码):
    状态转移方程:
    dp[j]=max(dp[j],dp[j-v[i]]+w[i])

    #include <iostream>
    #include <cstring>
    using namespace std;
    const int N = 1e3 + 50;
    int dp[N], w[N], v[N];
    int main()
    {
        memset(dp, 0, sizeof dp);//每个元素初始化0
        int n, m;
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
          cin >> v[i] >> w[i];
        for (int i = 1; i <= n; i++)// 枚举物品
          for (int j = m; j >= v[i]; j--)// 01背包的第二维
            for (int k = 0; k * v[i] <= j; k++)//枚举到底拿几个物品
              if (j - k * v[i] >= 0)
                dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);
        cout << dp[m] << endl;
        return 0;
    }
    

    但是不难发现,这份代码一定会TLE,数据范围是1000,而这个时间复杂度为1000 x 1000 x 1000接近1e9了,一定会超时的。
    换种思路。
    01背包就地滚动,每一次转移都用的第 i 个物品没算入背包中的状态,第二维是从m -> v[i] 的,当前算的是放入还是不放入第 i 个物品时的最大价值,我们只要把顺序改成 v[i] -> m 即可,表示的就是第 i 个物品被算过了,并且可以忽略掉应该选几个。为什么把顺序变一下就可以实现呢,分析一下状态转移方程。
    dp[j]=max(dp[j],dp[j-v[i]]+w[i]) 在完全背包中,第二维是 v[i] -> m 当前状态是由 dp[j-v[i]]+w[i] 转移过来的,但是循环顺序是从v[i] -> m,也就是说,到m之前,这个状态是已经被算过的,即:第 i 个物品已经被考虑过选还是不选,选几个了。代码实现:

    #include <iostream>
    using namespace std;
    const int N = 1e3 + 50;
    int dp[N], w[N], v[N];
    int main()
    {
        int n, m;
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
          cin >> v[i] >> w[i];
        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]);
        cout << dp[m] << endl;
        return 0;
    }
    
  • 相关阅读:
    摆花
    关于我的博客
    博客美化更新日志
    页面美化代码1.x
    本人已转至新博客!
    回归博客园
    退役快乐
    Luogu神贴合辑
    代码高亮预览
    NOIp2018普及组初赛解题报告
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294216.html
Copyright © 2020-2023  润新知