[算法总结] 动态规划 -- 背包背包!

1. 01背包题目介绍

有 N 件物品和一个容量为 V 的背包,每件物品有各自的价值且只能被选择一次,

要求在有限的背包容量下,装入的物品总价值最大。

思路:

  • 迭代n次 枚举每次物品在每个体积的拿法
  • 迭代m次 枚举能拿的体积
  • 条件判断 如果枚举的体积小于本身的体积那么拿不起 所以我们只能 = f[i-1][j]
  • 如果我们能拿的起,那么我们需要和f[i-1][j-v[i]]+w[i]来比较

代码实现(二维背包):

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 = 1; j <= m; j++)
    {
        当前背包容量装不进第i个物品,则价值等于前i-1个物品
        if(j < v[i]) 
            f[i][j] = f[i - 1][j];
         能装,需进行决策是否选择第i个物品
        else    
            f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
    }           

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

一维变化:

变化过程:

  • 观察动态规划方程可以发现f[i - 1][j], f[i - 1][j - v[i]] + w[i] 都只用到了i-1层而已
  • 但是因为我们需要使用到上一层状态所以需要从大到小枚举
 int main() {
    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--) 
            f[j] = max(f[j], f[j-v[i]]+w[i]);
    cout << f[m] << endl;
 return 0;    
}

2.完全背包题目介绍

有 N 件物品和一个容量为 V 的背包,每件物品有各自的价值且可以任意选择N次,

要求在有限的背包容量下,装入的物品总价值最大。

思路(记忆是可以这么记忆,但是理解过来还是挺复杂的):

  • 将01背包的一维表示的第二层循环 反过来

代码实现

int v[N],w[N];
 int main() {
    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 << f[m] << endl;
 return 0;    
}

多重背包1

题目描述:

也就是将01背包的 每个物品只能选一次换成了 每个物品能选s(给定)次

思路:
从01背包的角度出发,同样的也是选和不选的问题
我们容易发现 多重背包可以分成 1~s种选法
然而每个选法又是选和不选两种状态所以最后还是01背包一样的问题

代码实现

cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i]>>s[i];

for(int i=1;i<=n;i++)
{
    for(int j=m;j>=0;j--)
    {
        for(int k=1;k<=s[i]&&k*v[i]<=j;k++) 这里剪枝优化一下
            f[j] = max(f[j],f[j-k*v[i]]+k*w[i]); 这里就是s种 对每种选法选和不选的一个集合
    }
}
cout<<f[m];

分组背包问题(其实和多重背包差不多em)

题目大意:

  • 给你n组 物品 (也就是引入了一个物品组的概念)
  • 然后输入每个物品组的大小(含有物品的多少),以及物品组内每个物品的体积,
  • 特定的 每个物品组内 你只能选一个物品
  • 最后问你最大价值

思路:
和多重背包差不多,我们将问题化小,
你会发现,这还不是01背包的问题吗,不就是物品组内的物品选和不选吗,
所以我们可以直接 三重循环 就像处理多重背包一样

代码实现:

    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        for(int j=0;j<s[i];j++)
        cin>>v[i][j]>>w[i][j];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=m;j>=0;j--)
        {
            for(int k=0;k<s[i];k++)
            {
                if(v[i][k]<=j) 装的下的情况下
                    f[j] = max(f[j],f[j-v[i][k]]+w[i][k]); 这里就是01背包一样的处理了
            }
        }
    }
    cout<<f[m]<<endl;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值