#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]倒推回去,求出方案。

搭建双塔

VIJOS

给出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]即为答案。

老师:看上去会超时

多♂人背包??

VIJOS luogu

求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就可以了。

金明的预算方案

luogu

有依赖关系的背包。
转移时,主件、附件作为一个整体来转移。分 多种情况:不买、只买主件、买一个主件和附件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

飞翔的小鸟

VIJOS luogu

最长上升子序列

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),所以复杂度为

[m^2 imes sum_{i = 1}^{m} s_i ]

加分二叉树

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(){
    
}
原文地址:https://www.cnblogs.com/Cao-Yucong/p/12220579.html