动态规划之背包问题

一、01背包
1.雏形:有N件物品和一个容量为v的背包,第i件物品体积为c[i],价值为w[i]。求怎样能使背包的物品价值最大?
2.特点:每件物品只有一件,可以选择放(1)或不放(0)
3.状态转移方程:
二维:F[i][v]=max{F[i-1][v],F[i-1][v-c[i]]+w[i]}
F[i][v]表示前i件物品恰放入一个容量为v的背包可获得的最大价值,
前者是不放第i件(前i-1件)放入容量为v的背包中的总价值,
后者是前i-1件的总价值+第i件的价值。
一维(空间优化):F[v]=max{F[v],F[v-c[i]]+w[i]}
4.例题
采药
input
输入的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),
用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。
接下来的M行每行包括两个在1到100之间(包括1和100)的整数,
分别表示采摘某株草药的时间(1 <= t <= T)和这株草药的价值(1 <= v <= 100000)。
output
输出包括一行,这一行只包含一个整数,
表示在规定的时间内,可以采到的草药的最大总价值。
input
100 5
77 92
22 22
29 87
50 46
99 90
output
133

#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
    int dp[1005]={0};
    int T,M;
    scanf("%d %d",&T,&M);
    for(int i=0;i<M;i++)
    {
        int t,v;
        scanf("%d %d",&t,&v);
        for(int j=T;j>=t;j--)
        {
            dp[j]=max(dp[j],dp[j-t]+v);
        }
    }
    printf("%d\n",dp[T]);
    return 0;
}

二、完全背包
1.雏形:有N件物品和一个容量为v的背包,每个物品都有无限件可用,第i件物品体积为c[i],价值为w[i]。
求怎样能使背包的物品价值最大?
2.特点:每件物品都有无数件可用。
3.状态转移方程:
二维:F[i][v]=max{F[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}
注:
顺序:我们顺序写,这里的max中的两项就是当前状态的值,因为每种背包都是无限的。当我们把i从1到N循环时,
f[v]表示容量为v在前i种背包时所得的价值,这里我们要添加的不是前一个背包,而是当前背包。
所以我们要考虑的当然是当前状态。
4.例题
input
XXX上山去采药。XXX有一个容量为m(1<=m<=1000)的背包,
他所采集的药材的总重量不能大于背包的容量。
已知共有n(1<=n<=1000 )种药材,每种药材都有无限多,
并且知道每种药材的重量w(1<=w<=m)及价值v(1<=v<=100000),
如何选择,才能使得采到的药材的总价值最大?
第1行为两个整数m和n,分别为背包的容量及药材的种数。
第2至n+1行每行两个整数w和v,分别表示每种药材的重量及价值。
output
能采到的药材的最大总价值
input
100 5
77 92
33 50
34 60
50 46
99 161
output
161

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int main()
{
    int dp[1005];
    int m,n;
    int w[1005];
    int v[100001];
    scanf("%d %d",&m,&n);
    for(int i=0;i<n;i++)
    {
        memset(dp,0,sizeof dp[1005]);
        scanf("%d %d",&w[i],&v[i]);
            for(int j=w[i];j<=m;j++)
       {
           dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
       }
    }
    printf("%d\n",dp[m]);
    return 0;
}

三、多重背包
1.雏形:有N件物品和一个容量为v的背包,每个物品都有无限件可用,第i件物品体积为c[i],价值为w[i]。
求怎样能使背包的物品价值最大?
2.特点:第i件物品最多有n[i]件。
3.状态转移方程:
二维:F[i][v]=max{F[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}

四、区别
1.01背包和完全背包
01背包是顺序,完全背包是逆序。

首先想想为什么01背包中要按照v=V..0的逆序来循环。
这是因为要保证第i次循环中的状态 dp[i][v]是由状态dp[i-1][v-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果dp[i-1][v-c[i]]。
而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果dp[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。
2.完全背包和多重背包
这两者很类似。多重背包的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。
部分参考http://www.cppblog.com/tanky-woo/archive/2010/07/31/121803.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态规划是一种将大问题分解为小问题进行解决的方法,背包问题动态规划中最经典的题型之一。背包问题分为三类:01背包、完全背包和多重背包。其中,01背包问题是最经典的背包问题,也是动态规划的入门级必学算法。\[1\] 动态规划解决背包问题的核心思想是将问题分解为若干个小问题,先求解子问题,然后从子问题的解得到原问题的解。与分治法不同的是,动态规划适用于有重叠子问题的情况,即下一阶段的求解是建立在上一阶段的解的基础上进行进一步求解。通过填表的方式,逐步推进,最终得到最优解。\[2\] 多重背包问题介于01背包和完全背包之间,可以将其转化为01背包或完全背包问题求解。对于某种品,如果其数量乘以单位体积大于背包容量,那么该品与背包之间是完全背包问题。而对于某种品,可以将其数量视为不同的品,然后按照01背包问题进行处理。这样的转化可以在数据范围较小时适用,但在数量较大时可能会导致超时。因此,可以采用更精炼的划分方案,如二进制拆分,来减少品分类的组数,从而优化算法的效率。\[3\] 总结来说,动态规划是一种解决背包问题的有效方法,通过将大问题分解为小问题,并利用子问题的解来求解原问题,可以得到背包的最优解。 #### 引用[.reference_title] - *1* *3* [【算法与数据结构】—— 动态规划背包问题](https://blog.csdn.net/the_ZED/article/details/104882665)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [动态规划算法解决经典背包问题](https://blog.csdn.net/m0_52110974/article/details/120122061)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值