动态规划法求0/1背包问题

思路
状态表示:
f[i][j]表示前i个物品在容量为j的背包下的最大价值

v[i]表示第i个物品的价值,w[i]表示第i个物品的重量
状态转换:
对于第i个物品
如果当前背包不可以装下这个物品,那么当前的f[i][j] = f[i - 1][j],也就是上一个状态的最大价值
如果当前背包可以装下这个物品,那么当前的f[i][j] = f[i - 1][j - v[i]] + w[i]和f[i - 1][j]取较大的那一个,
第一个是考虑把第i个物品装入背包,那么背包物品的价值就是前i-1个物品装入容量为j-w[i]再加上第i个物品v[i]的价值,第二个是不把当前物品装入背包的价值,两个取大的那一个作为最优解
代码详解:

  1. 0/1背包问题
#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N], w[N], v[N];
int main()
{
    int n, c;
    cin >> n >> c;
    for(int i = 1; i <= n; i ++ )cin >> v[i] >> w[i];
    for(int i = 1; i <= n; i ++)
        for(int j = c; j >= 0 && j >= v[i]; j --)
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    cout << f[c] << endl;
    
    return 0;        
}       
}

完全背包问题(每个物品可以使用无数次f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i])
完全背包问题本来应该是在背包问题上再加一个循环的,
但是可以推导出下面这个样子
f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i])
为什么呢, 只是把0/1背包问题的f[i - 1][j - v[i] + w[i])的i-1换成了i就可以了?

从头来说:
完全背包问题, 对于第i个物品, 假设剩下的背包容量还可以装n个这个物品, 那么一共就有n+1中决策方案, 还有一种方案就是一个都不选
那么对于第i个物品:
它的最大价值就是f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]), f[i - 1][j - 2 * v[i]] + 2 * w[i]....)一直到n为止(①式)
令 j = j - v[i] 那么 f[i][j - v[i]] = max(f[i - 1][j - v[i]], f[i - 1][j - 2 * v[i]] + w[i].....) (②式)然后发现二式中的右边比较像一式中的第二项到最后一项, 就是每一项都少了一个w[i]
把二式带入一式,那么一式就是 f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]), 就是下面这个状态方程啦🤗;


#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N][N], w[N], v[N];
int main()
{
    int n, c;
    cin >> n >> c;
    for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i];
    for(int i = 1; i <= n; i ++ )
    {
        for(int j = 1; j <= c; j ++ )
        {
            f[i][j] = f[i - 1][j];
            if(j >= v[i])f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
        }
    }
    cout << f[n][c] << endl;
    return 0;
}

完全背包优化:

#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N], w[N], v[N];
int main()
{
    int n, c;
    cin >> n >> c;
    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 <= c; j ++ )//从前往后更新
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    cout << f[c] << endl;
    return 0;
}
posted @ 2021-05-23 22:01  梨花满地  阅读(228)  评论(0)    收藏  举报