1. 风铃重排问题解析与C++实现
作为一名长期从事算法竞赛辅导的教练,我发现风铃重排问题(P3621 [APIO2007])是考察树形结构和深度优先搜索(DFS)应用的经典题目。这个问题不仅考验选手对递归遍历的理解,还需要巧妙处理树形结构中的层级关系。下面我将从问题本质到代码实现,详细拆解这个问题的解决思路。
1.1 问题核心要求分析
题目给出一个由杆和玩具组成的风铃结构,要求通过交换杆的左右连接线,满足两个条件:
- 所有玩具位于同一层或相邻层(深度差≤1)
- 若玩具位于不同层,则左侧玩具必须比右侧玩具更深
关键在于理解"交换"操作的实际影响——每次交换一个杆的左右连接线,相当于翻转该杆的整个子树。这与二叉树旋转操作有相似之处,但更为简单。
1.2 数据结构建模
风铃结构天然适合用二叉树表示:
- 每个杆对应一个树节点
- 左右连接线对应左右子节点
- 玩具对应叶子节点(用-1表示)
示例输入对应的树结构如下:
code复制 1
/ \
2 3
/ \ / \
-1 4 5 6
| | |
-1 -1 -1
2. 算法设计思路
2.1 深度检查阶段
首先需要确定所有叶子节点的深度范围:
cpp复制void dfs(int u, int k) {
if(u == -1)
return (mi=min(mi, k)), (ma=max(ma, k)), void();
dfs(son[u][0], k+1);
dfs(son[u][1], k+1);
}
这段代码执行以下操作:
- 递归遍历树结构
- 遇到叶子节点(u == -1)时,更新最小深度mi和最大深度ma
- 时间复杂度:O(n),每个节点访问一次
关键点:若ma-mi > 1,直接输出-1,因为无法通过交换满足深度差≤1的条件
2.2 交换计数阶段
当深度差正好为1时,需要统计必要的交换次数:
cpp复制int dfs2(int u, int k) {
if(u == -1) return (k != mi);
int x = dfs2(son[u][0], k+1);
