1. 基环树问题实战:从快餐店选址到环路规划
最近在刷算法题时,遇到了几个有趣的基环树问题,记录下解题思路和代码实现。基环树作为树和环的结合体,在算法竞赛中经常出现,掌握其处理方法对提升解题能力很有帮助。
1.1 [NOI2013] 快餐店问题解析
原题要求在一棵基环树上找到一个位置设立快餐店,使得所有节点到该位置的最大距离最小。这个问题看似简单,但结合基环树的特性就变得有趣起来。
对于普通树的情况,答案显然是树的直径的中点。但当图中存在环时,情况就复杂多了。我的解题思路分为以下几个步骤:
- 基环树识别:使用DFS遍历找出图中的环
- 子树处理:对环上每个节点的子树进行DFS,计算最大深度
- 环上信息预处理:计算四种关键信息:
- 前缀+最大子树深度
- 前缀中最大深度两点+两点间距离
- 当前点深度+后缀长度
- 后缀中最大深度两点+两点间距离
核心难点在于处理环上路径的最优解。通过预处理这些信息,我们可以在O(n)时间内找到最优位置。
cpp复制#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
struct edge{
int nxt, to, val;
}e[N << 1];
int head[N], tot;
void add(int x, int y, int z){
e[++tot].val = z;
e[tot].to = y;
e[tot].nxt = head[x];
head[x] = tot;
}
// 其余代码见原始记录
实际编码时,有几个关键点需要注意:
- 环的识别要准确,避免漏掉边
- 子树深度的计算要考虑所有分支
- 四种信息的预处理顺序不能错
1.2 城市环路问题解法
这个问题类似于"没有上司的舞会",但加入了环的限制。我的解决思路是:
- 找到环中的一条边
- 分别以这条边的两个端点作为根进行树形DP
- 比较两种情况的结果取最大值
cpp复制#include <bits/stdc++.h>
#define int long long
