动态规划之背包问题
2017-01-21 14:55
176 查看
一、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
二、完全背包
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
三、多重背包
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
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(i b168 nt 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
相关文章推荐
- thinkphp分页
- POJ 2886 Who Gets the Most Candies? (线段树)
- 单例模式的七种写法(转载)
- 【剑指offer】面试题36-数组中的逆序对
- Selenium-java-框架启动主流浏览器
- PostgreSQL9.3+PostGIS2.1安装配置
- 几种导入osm(openstreetmap)数据的方法
- JAVA之sort()排序
- Eclipse快捷键
- android6.0SDK 删除HttpClient的相关类的解决方法
- python列表推导式
- python之连接oracle数据库
- telnet master主机的NodePort服务不通的问题
- 2016项目小总结
- C#不登录电脑启动程序
- 学习python:实例2.用PIL生成随机验证码
- VTK修炼之道17:图像基本操作_图像信息的访问与修改(vtkImageData)
- Java方式实现二叉树的前中后序遍历的递归及非递归算法
- Swift NSUserDefaults本地数据保存
- 数论之素数(质因数分解与筛法)