GESP 六级明日冲刺:最后一晚只抓两个大方向


GESP 六级明日冲刺:最后一晚只抓两个大方向

一、第一重点:树形 DP

为什么我认为树形 DP 必须重点准备?

因为 6 月份六级的第二道编程题就是树形 DP

《满二叉树》

题目给出一棵有根二叉树,要求统计所有子树中有多少棵是满二叉树。

参考程序非常典型:

复制代码
void dfs(int u) {
    if (!u)
        return;

    dfs(l[u]);
    dfs(r[u]);

    h[u] = max(h[l[u]], h[r[u]]) + 1;

    chk[u] = chk[l[u]]
          && chk[r[u]]
          && (h[l[u]] == h[r[u]]);

    ans += chk[u];
}

这里实际上就是一个非常标准的:

DFS + 子树信息 + DP

的树形 DP。


二、学生今晚必须重温一下树形 DP

不要再花时间背很多奇怪的树 DP。

只要把下面这个思想吃透:

"先问孩子,再算自己。"

例如:

复制代码
             1
           /   \
          2     3
         / \
        4   5

计算节点 1 时,我们必须先知道:

复制代码
2号节点的情况
3号节点的情况

所以:

复制代码
dfs(2);
dfs(3);

// 根据 2、3 的结果计算 1

这就是树形 DP 最核心的思想:

DFS 负责从下往上走,DP 负责保存每棵子树的信息。


三、明天树 DP 如果变形,学生要会认

考试不一定再问"满二叉树"。

可能换成:

  • 求每棵子树的节点数量

  • 求每棵子树的高度

  • 求每棵子树的最大值

  • 求每棵子树的和

  • 判断某个性质

  • 统计满足条件的子树

  • 求树上的最大路径

  • 求选择若干节点的最大价值

  • "选父节点就不能选儿子"之类的问题

但是核心套路仍然可能是:

复制代码
void dfs(int u)
{
    dfs(left);
    dfs(right);

    // 利用孩子的信息
    // 计算 u 的信息
}

给学生一句口诀:

树形 DP:孩子先算,父亲后算;
DFS 往下走,DP 往上收。


四、第二重点:背包 DP

这一部分我认为明天一定要复习到"看到题目就能判断 0/1 还是完全背包"

因为 6 月份六级选择题第 15 题直接考了:

0/1 背包的一维动态规划

代码中的关键就是:

复制代码
for (int i = 0; i < n; ++i)
{
    for (int w = W; w >= wt[i]; --w)
    {
        dp[w] = max(dp[w],
                     dp[w - wt[i]] + val[i]);
    }
}

6 月份第一道编程题《条形蛋糕》本身就是完全背包思想。


五、6 月份编程题 1:《条形蛋糕》

这是明天学生必须重新看一遍的题。

题意是:

有一条长度为 n 的蛋糕。

长度为 i 的蛋糕块售价为 p[i]

可以把蛋糕切成若干段,要求:

所有蛋糕块长度都是整数,求最大销售价格。

例如 6 月份样例中:

复制代码
n = 4

价格:
1 5 8 9

程序:

复制代码
int dp[1010], p[1010];

int main()
{
    int n;
    cin >> n;

    for (int i = 1; i <= n; ++i)
        cin >> p[i];

    for (int i = 1; i <= n; ++i)
    {
        for (int j = i; j <= n; ++j)
        {
            dp[j] = max(dp[j],
                        dp[j - i] + p[i]);
        }
    }

    cout << dp[n] << endl;

    return 0;
}

六、为什么《条形蛋糕》是完全背包?

这个问题明天非常可能帮助学生判断题型。

比如:

复制代码
长度 1 → 价格 1
长度 2 → 价格 5
长度 3 → 价格 8
长度 4 → 价格 9

一条长度 4 的蛋糕可以:

复制代码
4

也可以:

复制代码
1 + 3

或者:

复制代码
2 + 2

甚至:

复制代码
1 + 1 + 1 + 1

注意:

长度 1 的蛋糕块可以使用很多次。

所以它不是 0/1 背包,而是:

完全背包。


七、明天看到背包题,先问自己一个问题

"一个物品能用几次?"

这是最重要的。

类型 使用次数 一维 DP 循环
0/1 背包 每种最多 1 次 w--
完全背包 每种可以很多次 w++

0/1 背包

复制代码
for (int i = 0; i < n; i++)
{
    for (int w = W; w >= wt[i]; w--)
    {
        dp[w] = max(dp[w],
                     dp[w-wt[i]] + val[i]);
    }
}

完全背包

复制代码
for (int i = 0; i < n; i++)
{
    for (int w = wt[i]; w <= W; w++)
    {
        dp[w] = max(dp[w],
                     dp[w-wt[i]] + val[i]);
    }
}

所以一定要记住:

0/1:从大到小。

完全:从小到大。

但不要只背方向。

真正原因是:

0/1 背包不能让同一个物品在这一轮被重复使用;完全背包允许重复使用。


八、6 月份第二道编程题:《满二叉树》

题目给出:

复制代码
n 个节点

每个节点:
左儿子编号
右儿子编号

然后要求:

统计所有子树中,有多少棵是满二叉树。

它的核心状态实际上只有两个:

复制代码
h[u]
chk[u]

其中:

复制代码
h[u]

表示:

u 这棵子树的高度。

而:

复制代码
chk[u]

表示:

u 这棵子树是不是满二叉树。


九、这个状态转移非常重要

对于节点 u

复制代码
h[u] = max(h[left], h[right]) + 1;

如果:

复制代码
左子树是满二叉树
并且
右子树是满二叉树
并且
左右子树高度相同

那么:

复制代码
chk[u] = true;

即:

复制代码
chk[u] =
    chk[left]
    && chk[right]
    && h[left] == h[right];

这就是非常漂亮的树形 DP:

复制代码
          u
        /   \
       L     R

      ↓     ↓
  已知L的信息
  已知R的信息

        ↓

    计算u的信息

十、我对明天两道编程题的"押题"建议

我给六级学生做最后一晚的优先级排序,这样安排:

★★★★★ 第一档

树形 DP

至少练会:

  1. 二叉树 DFS

  2. 子树高度

  3. 子树节点数量

  4. 子树和

  5. 判断某种性质

  6. dfs(left); dfs(right); 后处理


★★★★★ 第二档

0/1 背包

一定会写:

复制代码
for (int i = 0; i < n; i++)
    for (int w = W; w >= wt[i]; w--)
        dp[w] = max(dp[w],
                     dp[w-wt[i]] + val[i]);

★★★★★ 第三档

完全背包

一定会写:

复制代码
for (int i = 0; i < n; i++)
    for (int w = wt[i]; w <= W; w++)
        dp[w] = max(dp[w],
                     dp[w-wt[i]] + val[i]);

6 月份《条形蛋糕》就是非常典型的完全背包模型。


十一、选择题复习看什么?

六级除了两道编程题之外,选择题覆盖了:

  • 继承与多态

  • 虚函数

  • 循环队列

  • 完全二叉树

  • 二叉树遍历

  • 哈夫曼

  • 格雷码

  • BFS

  • BST

  • 线性 DP

  • 0/1 背包


十二、明天考前最后复习清单

我要求大家拿着这张清单过一遍:

DP

  • dp[i] 到底表示什么?

  • 初始化是什么?

  • 状态转移是什么?

  • 最终答案在哪里?

  • 0/1 背包为什么倒序?

  • 完全背包为什么正序?

  • TreeNode

  • 左右孩子

  • dfs(u)

  • 空节点 if (!u) return

  • 先 DFS 子树

  • 再计算当前节点

  • 高度

  • 子树大小

  • 子树和

  • 判断子树性质

二叉树

  • 前序:根左右

  • 中序:左根右

  • 后序:左右根

  • 层序:BFS + queue

  • 完全二叉树

  • BST

STL

  • stack

  • queue

  • priority_queue

  • sort

  • vector

C++

  • 指针

  • 引用

  • 继承

  • 虚函数

  • 虚析构

  • 构造函数不能是 virtual

判断题也会考到构造函数、析构函数、stack::pop()、BST、完全二叉树、非递归前序遍历以及 DP 等内容。


十三、最后给六级学生一句话

明天如果第一道编程题看到"选物品、容量、价值、次数",先想背包;

如果看到"节点、儿子、子树、整棵树的信息",先想 DFS + 树形 DP。

不要怕题目换皮。

题目可以换故事、换数据、换问法,但算法的骨架不会凭空消失。

6月份的考题,提供了非常清晰的训练样本:

第一题《条形蛋糕》→ 完全背包

第二题《满二叉树》→ 树形 DP

这两道题正好可以作为明天考前的最后一轮"模型识别训练"

所以今晚最有效的方式不是再刷 20 道新题,而是把这两道 6 月真题真正做到"能读懂、能手推、能默写核心代码、能解释每一行为什么这样写"。

如果明天真的出现树形 DP + 0/1/完全背包,大家就有很大的机会把这 50 分的编程题稳住;即使题型发生变化,这套"识别模型 → 写状态 → 写转移"的能力也仍然能用。


相关推荐
神仙别闹2 小时前
基于 QT(C++)开发的地铁换乘系统
数据库·c++·qt
Dr_Fourier3 小时前
mmap的使用与底层原理
linux·c++
Tairitsu_H3 小时前
[C++] C++11右值引用与移动语义揭秘
开发语言·c++·c++11·右值引用·移动语义
(Charon)3 小时前
【C++】 定时器进阶:多层时间轮原理与任务迁移
c++
蒸蒸yyyyzwd3 小时前
cpp 选手备战秋招学习笔记 day32
c++·笔记·面试
汉克老师3 小时前
GESP 四级明日冲刺:最后一晚只抓两个大方向
c++·gesp·小学生·学c++编程
一木 之林4 小时前
第 3 节 在 AI 行业中,C/C++ 编程中的动态库和静态库
c语言·c++·后端
库玛西4 小时前
深度解构高并发利器:纯事件驱动 Reactor 模式的设计哲学与工程实践
服务器·开发语言·c++·笔记·tcp/ip
linx2954 小时前
单元五 · 对称认知·下:编译与链接
linux·c语言·开发语言·c++·嵌入式硬件