背包dp
一大波模板正在靠近
1.01背包
问题:有n件物品和一个容量为v的背包,第i件物品的费用(即体积)是w[i],价值是v[i],求解将哪些物品装入背包可使这些物品的费用和不超过背包容量,且价值总和最大。
动态转移方程为f[j]=max(f[j],f[j-w[i]]+v[i]),注意关于背包容量要倒着循环,来保证每个物品只选一次
//二维
for(int i=;i<=n;i++)
for(int j=m;j>=;j--)
f[i][j]=max(f[i-][j],f[i-][j-w[i]]+v[i]);
cout<<f[n][m];
//一维
for(int i=;i<=n;i++)
for(int j=m;j>=;j--)
f[j]=max(f[j],f[j-w[i]]);
cout<<f[m];
2.完全背包
问题:有n种物品和一个容量为v的背包,每种物品都有无限件可用,第i种物品的费用是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
动态转移方程为f[j]=max(f[j],f[j-w[i]]+v[i]),完全背包问题与01背包问题只有背包容量的循环次序不同
/*完全背包(无限件可用)*/
for(int i=;i<=n;i++)
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);
3.多重背包
问题:有n种物品和一个容量为v的背包,第i种物品最多有s[i]件可用,每件的费用是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
//朴素算法
for(int i=;i<=n;i++)
for(int j=m;j>=;j--)
for(int k=;k<=s[i];k++)
{
if(j-w[i]*k<)break;
f[j]=max(f[j],f[j-w[i]*k]+v[i]*k);
}
cout<<f[m];
//二进制优化,转换为01背包
int n1=;
for(int i=;i<=n;i++)
{
cin>>vv>>ww>>s;
int t=;
while(s>=t)
{
w[++n1]=ww*t;
v[n1]=vv*t;
s-=t;
t*=;
}
w[++n1]=ww*s;
v[n1]=vv*s;
}
for(int i=;i<=n1;i++)
for(int j=m;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+v[i]);
cout<<f[m];
4.混合三种背包问题
问题:有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包),该怎么求解呢?
//朴素
for(int i=;i<=n;i++)
{
if(s[i]==-)//完全背包
{
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
else
{
for(int k=;k<=s[i];k++)//循环件数
for(int j=m;j>=w[i];j--)
f[j]=max(f[j],f[k-w[i]]+v[i]);
}
}
cout<<f[m];
//二进制优化
for(int i=;i<=n;i++)
{
int ww,vv,ss;
int t=;
cin>>ww>>vv>>ss;
if(ss==-)
{w[++n1]=ww;v[n1]=vv;s[n1]=-;continue;}
if(ss==)
{w[++n1]=ww;v[n1]=vv;s[n1]=;continue;}
if(ss>)//多重背包
{
int t=;
while(ss>=t)
{
w[++n1]=ww*t;
v[n1]=vv*t;
s[n1]=;
ss-=t;
t*=;
}
if(ss>){
w[++n1]=ww*ss;
v[n1]=vv*ss;
s[n1]=;
}
continue;
}
}
for(int i=;i<=n1;i++)
{
if(s[i]==-)//完全背包
{
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
else
{
for(int j=m;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
}
cout<<f[m];
5.二维费用背包
问题:二维费用的背包问题是指对于每件物品,具有两种不同的费用,选择这件物品必须同时付出这两种代价,对于每种代价都有一个可付出的最大值(背包容量),求选择物品可以得到最大的价值。设第i件物品所需的两种代价分别为w1[i]和w2[i],两种代价可付出的最大值(两种背包容量)分别为V和U,物品的价值为v[i]。
状态转移方程为:
f[i][j][k]=max(f[i-1][j][k],f[i-1][j-w1[i]][k-w2[i]]+v[i]);
/*二维费用的背包问题(与01背包相似)*/
for(int i=;i<=n;i++)
for(int j=m1;j>=w1[i];j--)
for(int k=m2;k>=w2[i];k--)
f[j][k]=max(f[j-w1[i]][k-w2[i]],f[i][j]);
cout<<f[m1][m2];
6.分组背包
问题:有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
算法:
这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}
使用一维数组的伪代码如下:
for 所有的组k//循环分组
for v=V..0//容量限制
for 所有的i属于组k//组内物品
f[v]=max{f[v],f[v-c[i]]+w[i]}
/*分组的背包问题*/
for(int i=;i<=n;i++)
{
int p;
cin>>w[i]>>v[i]>>p;
a[p][++a[p][]]=i;
}
for(int k=;k<=t;k++)
for(int j=m;j>=;j--)
for(int i=;i<=a[k][];i++)
{
int tmp=a[k][i];//tmp代表k组中的第i个物品在所有物品中的序号
f[j]=max(f[j],f[j-w[tmp]]+v[tmp]);
}
cout<<f[m];
7.背包问题的方案总数
对于一个给定了背包容量、物品费用的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数。对于这类改变问法的问题,一般只需将状态转移方程中的max改成sum即可。例如若每件物品均是0-1背包中的物品,转移方程即为f[j]=sum{f[j],f[j-w[i]]+v[i]},即f[j]+=f[j-w[i]],初始条件f[0]=1。
事实上,这样做可行的原因在于状态转移方程已经考察了所有可能的背包组成方案.
/*背包问题的方案总数*/
//01背包求方案总数
for(int i=;i<=n;i++)
for(int j=m;j>=w[i];j++)
f[j]+=f[j-w[i]];
cout<<f[m];
背包dp的更多相关文章
- 背包dp整理
01背包 动态规划是一种高效的算法.在数学和计算机科学中,是一种将复杂问题的分成多个简单的小问题思想 ---- 分而治之.因此我们使用动态规划的时候,原问题必须是重叠的子问题.运用动态规划设计的算法比 ...
- hdu 5534 Partial Tree 背包DP
Partial Tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...
- HDU 5501 The Highest Mark 背包dp
The Highest Mark Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...
- Codeforces Codeforces Round #319 (Div. 2) B. Modulo Sum 背包dp
B. Modulo Sum Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/577/problem/ ...
- noj [1479] How many (01背包||DP||DFS)
http://ac.nbutoj.com/Problem/view.xhtml?id=1479 [1479] How many 时间限制: 1000 ms 内存限制: 65535 K 问题描述 The ...
- HDU 1011 树形背包(DP) Starship Troopers
题目链接: HDU 1011 树形背包(DP) Starship Troopers 题意: 地图中有一些房间, 每个房间有一定的bugs和得到brains的可能性值, 一个人带领m支军队从入口(房 ...
- BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )
题意保证了是一个置换群. 根据burnside引理, 答案为Σc(f) / (M+1). c(f)表示置换f的不动点数, 而题目限制了颜色的数量, 所以还得满足题目, 用背包dp来计算.dp(x,i, ...
- G - Surf Gym - 100819S -逆向背包DP
G - Surf Gym - 100819S 思路 :有点类似 逆向背包DP , 因为这些事件发生后是对后面的时间有影响. 所以,我们 进行逆向DP,具体 见代码实现. #include<bit ...
- 树形DP和状压DP和背包DP
树形DP和状压DP和背包DP 树形\(DP\)和状压\(DP\)虽然在\(NOIp\)中考的不多,但是仍然是一个比较常用的算法,因此学好这两个\(DP\)也是很重要的.而背包\(DP\)虽然以前考的次 ...
- 【BZOJ1004】【HNOI2008】Cards 群论 置换 burnside引理 背包DP
题目描述 有\(n\)张卡牌,要求你给这些卡牌染上RGB三种颜色,\(r\)张红色,\(g\)张绿色,\(b\)张蓝色. 还有\(m\)种洗牌方法,每种洗牌方法是一种置换.保证任意多次洗牌都可用这\( ...
随机推荐
- Java for LeetCode 123 Best Time to Buy and Sell Stock III【HARD】
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- ceph分布式存储系统初探
前言 由于公司的业务调整,现在我又要接触ceph这个东西,由于我接手的是一个网盘类项目,所以分布式存储系统ceph就是我必须要学的了.现在压力还是比较大的,从业务直接到后台核心. 大概在这几天,我将c ...
- 多线程(一) NSThread
OS中多线程的实现方案: 技术 语言 线程生命周期 使用频率 pthread C 程序员自行管理 几乎不用 NSthread OC 程序员自行管理 偶尔使用 GCD C 自动管理 经常使用 NSOpe ...
- 51nod 80分算法题
1537:见前几篇. 1627:题意:给定n,m的网格(10^5),初始状态为(1,1),你每次可以瞬移到右下方(不可以同行同列逗留)任何一个方格里,求移动到n,m的方案数. 一句话题解:首先很容易想 ...
- BZOJ 2101 [Usaco2010 Dec]Treasure Chest 藏宝箱:区间dp 博弈【两种表示方法】【压维】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2101 题意: 共有n枚金币,第i枚金币的价值是w[i]. 把金币排成一条直线,Bessie ...
- js的内部类
JavaScript中本身提供一些,可以直接使用的类,这种类就是内部类.主要有: Object/Array/Math/Boolean/String/RegExp/Date/Number共8个内部类. ...
- 五年java工作应具备的技能
具有一到五年开发经验 需要学习内容很多 JVM/分布式/高并发/性能优化/Spring MVC/Spring Boot/Spring Cloud/MyBatis/Netty源码分析等等等 01.透彻理 ...
- 0x01
随便记录点想法什么的, 这个博客的编辑界面挺简陋的...
- Linux网络编程socket错误分析
socket错误码: EINTR: 阻塞的操作被取消阻塞的调用打断.如设置了发送接收超时,就会遇到这种错误. 只能针对阻塞模式的socket.读,写阻塞的socket时,-1返回,错误号为INTR.另 ...
- 用rem适配移动端
常见方式: 1. 固定宽度(320)做法:这样前端倒是爽了,可是大页面两边有留白,小页面图标文字又会缩的很小,用户体验极其不好. 2. 流式布局:其实就是用%,这样宽度倒还差不多,高度怎么搞?所以这种 ...