HZNU-ACM寒假集训Day7小结 背包DP
背包问题
01背包
状态:f(i,j) 表示只能装前i个物品的情况下,容量为j的背包所能达到的最大总价值
状态转移方程: f(i,j)=max(f(i-1,j),f(i-1,j-w[i])+v[i])
核心代码(滚动数组) 由于我们使用一维数组存储,则在求两个子问题时没有直接取出那么方便了,因为第i次循环可能覆盖第i-1次循环的结果
“相反,如果在执行第 i 次循环时,背包容量按照0..V的顺序遍历一遍,来检测第 i 件物品是否能放。此时在执行第i次循环 且 背包容量为v时,此时的f[v]存储的是 f[i - 1][v] ,但是,此时f[v-weight[i]]存储的是f[i][v-weight[i]]。
因为,v > v - weight[i],第i次循环中,执行背包容量为v时,容量为v - weight[i]的背包已经计算过,即f[v - weight[i]]中存储的是f[i][v - weight[i]]。即,对于01背包,按照增序枚举背包容量是不对的。”
for (int i = ; i <= n; i++) {
for (int j = m; j >= w[i]; j--) {
f[j] = max(f[j], f[j - w[i]] + v[i]);
}
}
但是,增序枚举会达到什么效果:它会重复的装入某个物体,而且尽可能的多使价值增大
01背包方案数问题
洛谷P1164 小A点菜 https://www.luogu.com.cn/problem/P1164
“
开个玩笑,这是一道简单的动规题,定义f[i][j]为用前i道菜用光j元钱的办法总数,其状态转移方程如下:
(1)if(j==第i道菜的价格)f[i][j]=f[i-1][j]+1;
(2)if(j>第i道菜的价格) f[i][j]=f[i-1][j]+f[i-1][j-第i道菜的价格];
(3)if(j<第i道菜的价格) f[i][j]=f[i-1][j];
”
code1
const int maxn = ;
int n, m, w[maxn], f[maxn][]; int main() {
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) {
scanf("%d", &w[i]);
}
for (int i = ; i <= n; i++) {
f[i][] = ;
} for (int i = ; i <= n; i++) {
for (int j = ; j <= m; j++) {
f[i][j] += f[i - ][j];
if (j >= w[i]) f[i][j] += f[i - ][j - w[i]];
}
} printf("%d", f[n][m]);
return ;
}
code2
const int maxn = ;
int n, m, w[maxn], f[]; int main() {
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) {
scanf("%d", &w[i]);
}
f[] = ; for (int i = ; i <= n; i++) {
for (int j = m; j >= w[i]; j--) {
f[j] += f[j - w[i]];
}
}
printf("%d", f[m]);
return ;
}
:
完全背包问题
状态转移方程: f(i,j)=max(f(i-1,j),f(i,j-w[i])+v[i]) 理由是当我们这样转换时,f(i,j-w[i])已经由f(i,j-2*w[i]) 更新过,那么f(i,j-w[i])就是充分考虑了第i件物品后的最优结果换言之,我们通过局部最优子结构的性质重复使用了之前的枚举过程,优化了枚举的复杂度。
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]);
}
}
多重背包问题
考虑二进制优化
时间复杂度O(NWlog∑mi)
luogu P1776 宝物筛选https://www.luogu.com.cn/problem/P1776
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
typedef long long ll;
using namespace std; const int maxn = ;
const int maxm = ; int n, m, ans, cnt = ;
int f[maxn];
int w[maxn], v[maxn]; int main() {
int a, b, c;
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) {
scanf("%d%d%d", &a, &b, &c);
for (int j = ; j <= c; j << ) {
v[++cnt] = j * a;
w[cnt] = j * b;
c -= j;
}
if (c) v[++cnt] = a * c, w[cnt] = b * c; //二进制优化 拆分
}
for (int i = ; i <= cnt; i++) {
for (int j = m; j >= w[i]; j--) {
f[j] = max(f[j], f[j - w[i]] + v[i]);
}
}
printf("%d\n", f[m]);
return ;
}
HDU 2844 Coins(多重背包)
注意:本题只关注“可行性”
因此不妨变换思路求解
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
typedef long long ll;
using namespace std; int vis[];
int a[];
int c[];
int f[]; int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
if (n == m && n == ) break;
memset(f, , sizeof f);
f[] = ;
for (int i = ; i<=n; i++) scanf("%d", &a[i]);
for (int i = ; i <=n; i++) scanf("%d", &c[i]);
for (int i = ; i <=n; i++) {
memset(vis, , sizeof vis);
for (int v = a[i]; v <= m; v++) {
if ((!f[v]) && (vis[v-a[i]] < c[i]) && f[v - a[i]]) {
vis[v] = vis[v - a[i]] + ;
f[v] = ;
}
}
}
int cnt = ;
for (int i = ; i <= m; i++) if (f[i]) cnt++;
printf("%d\n", cnt);
}
return ;
}
分组背包 (三重循环)
状态转移方程 f(k,v)=max(f(k-1,v),f(k-1,v-ci)+wi|i属于group k)
时间复杂度O(NV)
HDU1712 ACboy needs your help
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
typedef long long ll;
using namespace std; int mp[][];
int f[];
int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
memset(f, , sizeof f);
if (n == && n == m) break;
for (int i = ; i <=n; i++) {
for (int j = ; j <=m; j++) {
scanf("%d", &mp[i][j]);
}
}
for (int i = ; i <=n; i++) {
for (int v = m; v>=; v--) {
for (int j =; j <=m; j++) {
if(v>=j) f[v] = max(f[v], f[v - j] + mp[i][j]);
}
}
}
printf("%d\n", f[m]);
}
return ;
}
初始化问题:
“初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。
如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。
如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。”
HZNU-ACM寒假集训Day7小结 背包DP的更多相关文章
- HZNU-ACM寒假集训Day6小结 线性DP
线性DP 考虑一组硬币面值 1,5,11 给定W,求凑出W的最少硬币个数 我们记凑出n需要用到的最少硬币数量为f(n) 我们注意到了一个很棒的性质 : f(n)只与f(n-1) f(n-5) f( ...
- 中南大学2019年ACM寒假集训前期训练题集(基础题)
先写一部分,持续到更新完. A: 寒衣调 Description 男从戎,女守家.一夜,狼烟四起,男战死沙场.从此一道黄泉,两地离别.最后,女终于在等待中老去逝去.逝去的最后是换尽一生等到的相逢和团圆 ...
- HZNU-ACM寒假集训Day10小结 树-树形DP
树形DP 加分二叉树 洛谷P1040 注意中序遍历的特点:当根节点编号k时,编号小于k的都在其左子树上,编号大于k的都在右子树 转移方程 f[i,j]=max{f[i,k-1]*f[k+1,j]+d[ ...
- 中南大学2019年ACM寒假集训前期训练题集(入门题)
A: 漫无止境的八月 Description 又双叒叕开始漫无止境的八月了,阿虚突然问起长门在这些循环中团长哪几次扎起了马尾,他有多少次抓住了蝉等等问题,长门一共回复n个自然数,每个数均不超过1500 ...
- HZNU-ACM寒假集训Day8小结 最小生成树
最小生成树(无向图) Kruskal 给所有边按从小到大排序 形成环则不选择(利用并查集) P1546 最短网络 https://www.luogu.com.cn/problem/P1546 #i ...
- HZNU-ACM寒假集训Day3小结 搜索
简单搜索 1.DFS UVA 548 树 1.可以用数组方式实现二叉树,在申请结点时仍用“动态化静态”的思想,写newnode函数 2.给定二叉树的中序遍历和后序遍历,可以构造出这棵二叉树,方法是根据 ...
- HZNU-ACM寒假集训Day1小结 STL 并查集
常用STL 1.优先队列 priority_queue 内部是用堆(heap)实现的 priority_queue<int> pq; 默认为一个“越小的整数优先级越低的优先队列” 对于一些 ...
- HZNU-ACM寒假集训Day12小结 数论入门 题解
算不出的等式 BJOI2012 看到这题 真没什么办法 无奈看题解 1.注意到p/q 联想到斜率 2.注意到 [ ] 联想到整点 注意到k在变化,构造一次函数 f(x)=p/q*x ,g(x)=q/p ...
- HZNU-ACM寒假集训Day12小结 数论入门
符号说明 a|b a整除b (a,b) a与b的最大公因数 [a,b] a与b的最小公倍数 pα||a pα|a但pα+1∤a a≡b(mod m) a与b对模m同余 a ...
随机推荐
- vue中使用矢量图
1.打开矢量图库,将需要的图表添加至购物车 2.将购物车的图标添加到一个项目中(便于后期增加更新)并下载至本地 3.将这四个文件及iconfont.css添加至项目的assets中 4.打开iconf ...
- 使用 Doxygen 生成文档 (以FFmpeg 4.1.1 为例)
背景 在查找 ffmpeg 文档的时候,发现其文档是根据 Doxygen 生成的. 为了学习方便,这里以 生成 ffmpeg 4.1 文档 为例. 注:为了兼顾 arm 与 host ,本人选择了同时 ...
- 2.24 模拟赛 + DIV2 总结
本来实在是不想打了,后来真的手痒. 晚上发现正进行DIV2然后就打了场,模拟,幸好没参加,逆风.排名2400 Codeforces Round #622 (Div. 2) A题十分钟过了 B题http ...
- echart 库 初始
一.echart简介 Echarts (http://echarts.baidu.com/)是百度公司出品的,算是百度不可多得的良心之作.要彻底掌握Echarts,你需要掌握一点前端开发的知识,这些知 ...
- vs2010编译C++ 状态标志
// CTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #include &l ...
- XV6源代码阅读-文件系统
Exercise1 源代码阅读 文件系统部分 buf.h fcntl.h stat.h fs.h file.h ide.c bio.c log.c fs.c file.c sysfile.c exec ...
- WAFの基本防护透明流模式v1.0
一.WAFの透明流模式 1)首先先配置WAF的网络,配置一个网桥接口,设置IP便于带内管理. 2)当然,如果需要不同网段之间都能够管 ...
- 将xml字符串的所有叶标签转换成Map集合
实际问题:对方服务器接口采用webservice方式返回xml报文,现需解析xml获取所有叶节点的标签名及携带的值 解决方案:利用dom4j解析xml并利用递归获取叶节点,将标签名及标签值封装到Map ...
- 062、Java中的方法重载
01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...
- 022、MySQL字符串的拼接
SELECT CONCAT('曾经沧海难为水-','-除却巫山不是云') #字符串拼接 SELECT CONCAT('AB','CD','EF'); #ABCDEF #字符串拼接 SELECT CON ...