n 只有 1000,枚举起点 DFS,维护路径黑点数和长度即可。
P11379 [GESP202412 八级] 树上移动
GESP8 冲刺课堂页:先建模,再压缩状态,最后读代码。
一、先回答问题
看到树上最长路径就套直径,但黑点限制会破坏普通直径性质。
二、核心观察
固定起点后,到每个终点的路径唯一,DFS 中路径状态足够判断合法。
为什么不丢答案:枚举所有起点,等价于枚举所有无重复简单路径的两个端点。
起点 s
黑点数
路径长度
三、互动演示
步骤1
关键状态 A-
关键状态 B-
答案/目标-
复杂度看表
课堂动作手推
点击下一步开始。
四、自己选答案
起点颜色算不算?
先判断,再点按钮。
为什么 O(n^2) 可过?
先判断,再点按钮。
五、手推结果
| 状态 | 含义 |
|---|---|
| u | 当前点 |
| b | 已过黑点数 |
| tot | 已过节点数 |
课堂要求:每题先说清对象、关系、保留的信息、压缩掉的信息,再写代码。
六、C++14 参考代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
vector<int> adj[MAXN];
int color[MAXN];
int n, k;
int ans = 0;
// u: 当前节点, p: 父节点, b: 当前路径黑点数, tot: 当前路径总点数
void dfs(int u, int p, int b, int tot) {
if (b > k) return; // 超过黑点限制,停止
ans = max(ans, tot); // 更新最大节点数
for (int v : adj[u]) {
if (v == p) continue;
dfs(v, u, b + color[v], tot + 1);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> color[i];
}
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
// 枚举每一个点作为起点
for (int i = 1; i <= n; i++) {
dfs(i, -1, color[i], 1);
}
cout << ans << endl;
return 0;
}