給定完全二叉樹,可交換任意節點左右子樹。求最少交換次數使所有葉子深度差 ≤ 1,且較深葉子全在較淺葉子左側。
DFS 返回值編碼子樹葉子類型:
轉移邏輯:
int l = dfs(left), r = dfs(right);
if (l == 3 || r == 3) no_solution(); // 子樹非法
// 查表決定是否需交換
// a[l][r] = 0: 不交換合法 1: 需交換 3: 非法
static const int a[4][4] = {
{0,0,0,0},
{0,0,0,0},
{0,1,0,1},
{0,1,0,0}
};
ans += a[l][r];
return l | r; // 合併類型:1|2=3(非法), 1|1=1, 2|2=2
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100100;
int n, ans = 0;
int max_dpt = 0, min_dpt = INT_MAX;
int ls[MAXN], rs[MAXN];
void dfs_depth(int u, int dpt) {
if (u == -1) {
max_dpt = max(max_dpt, dpt);
min_dpt = min(min_dpt, dpt);
return;
}
dfs_depth(ls[u], dpt + 1);
dfs_depth(rs[u], dpt + 1);
}
int dfs_dp(int u, int dpt) {
if (u == -1) return (dpt == min_dpt) ? 2 : 1;
int l = dfs_dp(ls[u], dpt + 1);
int r = dfs_dp(rs[u], dpt + 1);
if (l == 3 && r == 3) { cout << -1 << endl; exit(0); }
static const int a[4][4] = {
{0,0,0,0}, {0,0,0,0},
{0,1,0,1}, {0,1,0,0}
};
ans += a[l][r];
return l | r;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) cin >> ls[i] >> rs[i];
dfs_depth(1, 1);
if (max_dpt - min_dpt >= 2) return cout << -1 << endl, 0;
if (max_dpt == min_dpt) return cout << 0 << endl, 0;
dfs_dp(1, 1);
cout << ans << endl;
return 0;
}