动态规划之背包问题(一)

155 阅读2分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

背包问题(dp)

化零散为整体,使用f(i,j)表示一大类集合

化整为零,f(i,j)是由谁转化来的(如何得出)

背包问题思维方式

首先确定f [ i , j ] 函数的定义

0011

确定定义后通过图片进行分析,列好f [ i , j ] 从实际意义出发考虑初始化

方案数问题

  • 考虑到前i个然后总和至多,不超过,小于等于j的时候f(所有)初始化成1
  • 考虑到前i个然后总和恰好等于j的时候f(O) = 1其余都是0
  • 考虑到前i个然后总和至少是j的时候f(O) = 1其余都是0转移的时候可以要j <v从f (0)转移过来所以j可以从0开始枚举

最大最小值问题

不超过

  • 考虑到前i个物品体积不超过,至多,小于等于j的所有方案的价值最大值f(所有) = 0
  • 所以体积不超过j的时候我们不讨论最小值

恰好等于

  • 考虑到前i个物品体积恰好等于j的所有方案的价值最大值f (0) = 0 f(其余) - 0x3f3f3f3f
  • 最小值f (0) =0f (其余) 0x3f3f3f3f

至少

  • 考虑到前i个物品体积至少是j的所有方案的价值最大值我们不讨论
  • 最小值f (0) = 0 f(其余) 0x3f3f3f3f状态转移j < v可以从0转过来

01背包

n个物品(每个物品只有一个),每个物品v体积,w价值,有m个背包,如何取价值最大化

分析:

F[ i , j ] = max ( F [ i - 1 , j ] , F [ i - 1 , j - v] + w )

该公式表示:F[ i , j ] 从前 i 个物品中选出了总体积为 j 的物品放入背包的最大价值和

​ F [ i - 1 , j ] 表示不选第 i 个物品的最大价值

​ F [ i - 1 , j - v ] + w (条件:j >= v) 表示不选第 i 个物品的最大价值

模板

求最大价值

优化前
#include <iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N][N];//用于表示F[i,j]
int n, m;
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ){
        int v, w;
        cin >> v >> w;
        for (int j = 1; j <= m; j ++ ){
            if(j - v >= 0) f[i][j] = max(f[i - 1][j], f[i - 1][j - v] + w);//如果有容量,就取最大值
            else f[i][j] = f[i - 1][j];
        }
    }
    cout << f[n][m] << endl;   
    return 0;
}
优化后
#include <iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N];
int n, m;
int main(){
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ){
        int v, w;
        cin >> v >> w;
        for (int j = m; j >= v; j -- ){
            f[j] = max(f[j], f[j - v] + w);//因为优化前只使用了i-1所以可以直接将二维数组转化为一维数组
        }
    } 
    cout << f[m] << endl;  
    return 0;
}

求方案数

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10010;
int n, m;
int f[N];//f[i,j]的含义是,前i个物品值为j的方案数
int main()
{
    cin >> n >> m;
    f[0] = 1;
    for (int i = 0; i < n; i ++ )
    {
        int v;
        cin >> v;
        for (int j = m; j >= v; j -- )
            f[j] += f[j - v];//max函数变成了+发
    }
    cout << f[m] << endl;
    return 0;
}