#QBXT2020寒假 Day 5
Day 5
几类背包问题
疯狂讲解
1.01背包
f[i][j]=max(f[i-1][j],f[i-1][j-t_i]+v_i)
4.二维DP
f[i][j][k]表示前i株中采集,用j个单位时间, 消耗k点体力值,最大价值。
f[i][j][k]
=max(f[i-1][j][k],f[i-1][j-t_i][k-e_i]+v_i)
5.分类DP
n株草药,每株有价值、采集时间、草药类别。 最多采集m个单位时间。相同类别的草药只能采一株, 求最大价值。
n≤100,m≤1000
f[i][j]表示前i类中采集,用j个单位时间,最大价值。
f[i][j]=max(f[i-1][j],f[i-1][j-t_u]+v_u)
u是i类的。
6.输出方案:链表储存
n株草药,每株有一个价值和采集时间。最多采 集m个单位时间。求最大价值,输出任意一种方案。
n≤100,m≤1000
f[i][j]表示前i株中采集,用j个单位时间,最 大价值。
f[i][j]=max(f[i-1][j],f[i-1][j-t_i]+v_i)
g[i][j] 表示g[i][j] 是从f[i-1][j] 还是f[i- 1][j-t_i]+v_i转移过来。
从g[n][m]倒推回去,求出方案。
搭建双塔
给出n个积木,每个积木有一个高度。
选出一些积木,将它们分成两组,每组的高度 和相等。
求最大高度和。
n≤100,积木高度和≤2000
CYC的思路是这样的
f[k][i]表示第i个积木放在第k个塔上
很显然不对 fuck
正解:
f[i][j]表示从前i个积木中选,两组高度差为j, 高度较小的那一组高度最大是多少。
f[i][j]=max(f[i-1][j], f[i-1][j+a_i]+a_i,f[i-1][|j-a_i|]+max(0,a_i-j))
f[n][0]即为答案。
老师:看上去会超时
多♂人背包??
求01背包的前k优解
相当于是求选出体积恰为V的方案中,价值前k 大的方案的价值和。
f[i][j][k]表示从前i个物品中选择,体积是j 的方案中价值第k大是几。
f[i][j][]从f[i-1][j][]和f[i-1][j-a_i][]转移。
每次更新的时候,枚举所有max(f[i-1] [j],f[i-1] [j-ai])排序,取前k个
那么会不会重复?
只需要把数组初始化为很大的值,然后f[0][0][1] = 0就可以了。
金明的预算方案
有依赖关系的背包。
转移时,主件、附件作为一个整体来转移。分 多种情况:不买、只买主件、买一个主件和附件1、 买一个主件和附件2、买主件和两个附件。
f[i][j]=f[i-1][j],f[i-1][j-aw]+av f[i-1][j-aw-bw]+av+bv
f[i-1][j-aw-cw]+av+cv
f[i-1][j-aw-bw-cw]+av+bv+cv
飞翔的小鸟
最长上升子序列
if(i > j && a[i] > a[j]) f[i] = max(f[j]) + 1;
最长公共子序列
f[i][j]表示从A中前i个数、B中前j个数中选择, 最长公共子序列长度。
f[i] [j]
=max(
f[i-1] [j],
f[i] [j-1],
f[i-1] [j-1] + 1 (if(ai == bi))
其他类型讲解
区间DP
环形DP
树形DP
数位DP
状态压缩DP
区间DP
合并果子
在一个果园里,多多已经将所有的果子打了下 来,而且按果子的不同种类分成了不同的n堆,排成 一排。多多决定把所有的果子合成一堆。
每一次合并,多多可以把相邻两堆果子合并到 一起,消耗的体力等于两堆果子的重量之和。可以 看出,所有的果子经过n-1次合并之后,就只剩下一 堆了。多多在合并果子时总共消耗的体力等于每次 合并所耗体力之和。
求最小体力消耗。 n≤100
贪心不就行了
f[i] [j]表示将i~j堆果子合成一堆需要的最小 体力值。
枚举最后一次合并的情况。 f[i] [j]=min(f[i] [k]+f[k+1] [j])+val[i] [j]
最后的答案就是f[1] [n]
一般形式:
以区间为端点设置f数组
矩阵取数游戏
每行都是独立的,所以每行单独来做就行。
考虑一行。
f[i] [j]表示i~j作为单独的一部分,按照规定 取,最大得分。
枚举取最左还是最右。 f[i] [j]=max( 2*(f[i+1] [j]+a[i])
2*(f[i] [j-1]+a[j]) )
高精度。
能量项链
复制一遍加在后面,就变成链上的了。
f[i] [j]表示将i~j聚合,最大是多少。 枚举最后一次聚合情况。 f[i] [j]=max(f[i] [k]+f[k+1] [j]+...)
项链
实际上是一个树结构。
f[i] [j]表示在i为根的子树中选j节课,最大学
分。
从子结点转移到根结点时,实际上相当于一个 序列上的DP。
每次访问一个点的时候访问他的所有子节点(Si),然后要访问M个节点,分组背包的复杂度是\(m^2\),所以复杂度为
加分二叉树
f[i] [j]表示i~j表示一棵树的中序遍历时,这棵树最大加分。
枚举根结点位置。
f[i] [j]=f[i] [k-1]*f[k+1] [j]+v[k]
i≤k≤j
至于先序遍历,实际上就是求方案。每个区间 都记录分界点,递归下去生成先序遍历。
互不侵犯
在N×N的棋盘里面放K个国王,使他们互不攻击, 共有多少种摆放方案。
国王能攻击到它上下左右,以及左上左下右上 右下八个方向上附近的各一个格子,共8个格子。
1 <=N <=9
** 异或:相同为0,不同为1 **
借机讲一下对拍
老师AC了就不讲了
好了老师开始讲对拍了
以a + b 为例子
首先我们写一个(自以为正确的)
然后我们写一个暴力解法
正解
#include <iostream>
using namespace std;
int a,b;
int main(){
cin >> a >> b;
cout << a + b;
}//lcez_cyc
再写暴力解
#include <iostream>
using namespace std;
int a,b,ans;
int main(){
cin >> a >> b;
while(a--) ans++;
while(b--) ans++;
cout << ans << endl;
return 0;
}
然后写数据生成器
#include <cstdio>
#include <algorithm>
using namespace std;
int main(){
}