完全背包问题(图解+代码 + 优化)

题目概述:

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

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

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

输入格式

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

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

输出格式

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

数据范围

0 0

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

10

核心思想

(子集划分不重不漏)

对于01背包问题,状态计算表示的子集划分为两部分,一部分所有选第i个物品的方案,另一部分为所有不选第i个物品的方案。

对于完全背包问题,状态计算表示的子集分为很多部分,第i个物品选1次的方案...选k次...。(即这所有的方案中取max)

对于核心代码的推导(闫老师)

完全背包问题(图解+代码 + 优化)_第1张图片

代码如下:

#include
using namespace std;
const int N = 1010;
int f[N][N];
int v[N], w[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 = 0; j <= m; j++)
        {
            f[i][j] = f[i - 1][j];
            if(j>=v[i])f[i][j]= max(f[i][j], f[i][j - v[i]] + w[i]);
            /*(实质为推导式)
            for (int k = 0; k * v[i] <= j; k++)
                f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);
                */
        }

    cout << f[n][m] << endl;
}

运行结果:

完全背包问题(图解+代码 + 优化)_第2张图片

优化方案(二维到一维)

1.f[j] = f[j] == f[i][j] = f[i - 1][j]
2.f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]) 等价于 f[j] = max(f[j], f[j - v[i]] + w[i]) (此处j从小到大循环没问题)

3.j>=v[i]的条件可以放在for循环中

优化代码如下:

#include
using namespace std;
const int N = 1010;
int f[N];
int v[N],w[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++)
    {
            f[j] = max(f[j],f[j-v[i]]+w[i]);
    }
    cout<

你可能感兴趣的:(Acwing,算法,c++,动态规划)