动态规划之背包模型及其扩展应用

前言

对于原始背包问题及其优化可以参见这篇博客
背包问题

背包问题的初始化问题

一般问题有以下三种情况
在这里插入图片描述
对应的初始化方法
在这里插入图片描述

  1. 对于体积最多是j, f [ 0 ] [ j ] f[0][j] f[0][j]表示一个物品都不选体积最多是j的情况,这个是存在的,所以置为0 ,对于循环中我们是最多是j,如果 v < 0 ,说明 v1 > j ,这是不存在的。
  2. 对于体积恰好是j, f [ 0 ] [ j ] f[0][j] f[0][j]表示一个物品都不选体积最多是j的情况,只有 f [ 0 ] [ 0 ] f[0][0] f[0][0]是存在的,其余的都是这个是不存在的,因此设置为一个不合法的数,至于是正无穷还是负无穷,取决于题目是求最大还是最小;对于循环边界理由和上面一样
  3. 对于初始化条件与第2个一样 ;对于循环条件,我们·是至少是j因此当v<0的时候是存在的,而它们的值是 v = 0 时候的值。

01背包

装箱问题

题目转送门

个人解题思路:

这题是让我们尽可能的让背包的剩余空间小,也就是放入的物品的体积要尽可能的大,因为物品只给了体积没有价值,那么我们就可能将每一个物品的价值等同于它的体积,那么这就转变为了01背包问题。那么这个 d p [ i ] dp[i] dp[i]表示总体积不超过背包容量下的最大体积,也就说剩余体积最小。

代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 35 , M = 20010;
int n , m ;
int w[N] , v[N] ,f[M];

int main(){
   
    cin>>m>>n;
    for(int i = 1 ; i <= n ; ++i)cin>>w[i] ;
    for(int i = 1; i <= n ; ++i)
        for(int j = m ; j >= w[i] ; --j)
            f[j] = max(f[j] , f[j-w[i]] + w[i]);
    cout<<m - f[m]<<endl;
    return 0;
}

宠物小精灵之收服

题目转送门

解题思路:

这题由单一花费变成了二维花费,我们的花费有精灵球的数量和体力,因此我们定义的是二维dp; d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示考虑前i个精灵,精灵球数量不超过j,体力不超过k的最大的精灵球数量。由背包问题我们可以将第一维的空间省略掉,采用逆序的遍历方式。对于二维我们还是有
在这里插入图片描述

对于剩余的体力,我们在 f [ N ] [ 1 − M ] f[N][1-M] f[N][1M]中选出等于 f [ N ] [ M ] f[N][M] f[N][M]的最小的体力,这是花费的最小体力。同时因为体力不能会0,我们再减1.

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 110 , M = 1010;
int n , m , K;
int w[N] , v[N] ,f[M][M] ;

int main(){
   
    cin>>m>>K>>n;
    for(int i = 1;  i <= n ; ++i)cin>>w[i]>>v[i];
    for(int i = 1 ; i <= n ; ++i)
        for(int j = m ; j >= w[i]; --j)
            for(int k = K  ; k > v[i]  ; --k )
                        f[j][k] = max(f[j][k] ,f[j-w[i]][k-v[i]] + 1);
    cout<<f[m][K]<<' ';
    int cnt = 0;
    for(int k = 1 ; k <= K  ; ++k)
        if(f[m][k] == f[m][K]){
   
            cnt = k - 1;
            break;
        }
    cout<<K - cnt <<endl;
    return 0;
}

数字组合

题目转送门

解题思路;

这是一个典型的0/1背包模型,N个正整数就是N个物品,M就是背包的容积。在外层循环到i时(表示从前i个数中选),设F[j]表示“和为j”有多少种方案。在具体实现中,只需要把原始代码中求max的函数改为求和即可。
代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110 , M = 10010;
int n , m ;
int w[N] , f[M];

int main(){
   
    cin>>n>>m;
    for(int i = 1; i <= n ; ++i)cin>>w[i];
    f[0] = 1;
    for(int i = 1; i <= n ; ++i)
        for(int j = m; j >= w[i] ; --j)
            f[j] += f[j-w[i]];
            
    cout<<f[m]<<endl;
    
    return 0;
}

开心的金明

题目转送门

解题思路:

这题我们可以将每一个物品的钱看成是体积,而物品的价值则是金额*重要程度。这样我们就转化成了01背包问题了、

代码;

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 50010;
int n , m;
int f[N];

int main
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落春只在无意间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值