查看: 27|回复: 0

洛谷P3365 改造二叉树:从问题分析到代码实现

[复制链接]
  • TA的每日心情

    昨天 16:28
  • 签到天数: 19 天

    [LV.4]偶尔看看III

    17

    主题

    0

    回帖

    49

    积分

    新手上路

    Rank: 1

    积分
    49
    发表于 3 天前 | 显示全部楼层 |阅读模式
    一、问题分析

    题目要求我们计算将二叉树修改为二叉搜索树(BST)所需的最少修改次数。二叉搜索树的性质是:对于任意节点,其左子树所有节点的值都小于该节点的值,右子树所有节点的值都大于该节点的值。

    二、解题思路
    • 中序遍历序列‌:BST的中序遍历结果是一个严格递增序列
    • ‌问题转化‌:将原二叉树的中序遍历序列转换为严格递增序列所需的最少修改次数
    • ‌最长递增子序列(LIS)‌:最少修改次数 = 序列长度 - 最长递增子序列长度

    三、C++代码实现
    1. #include <iostream>
    2. #include <vector>
    3. #include <algorithm>
    4. using namespACe std;

    5. struct TreeNode {
    6.     int val;
    7.     TreeNode *left;
    8.     TreeNode *right;
    9.     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    10. };

    11. // 构建二叉树
    12. TreeNode* buildTree(int n, const vector<int>& vals, const vector<pair<int, int>>& edges) {
    13.     vector<TreeNode*> nodes(n + 1);
    14.     for (int i = 1; i <= n; ++i) {
    15.         nodes[i] = new TreeNode(vals[i - 1]);
    16.     }
    17.    
    18.     for (int i = 2; i <= n; ++i) {
    19.         int fa = edges[i - 2].first;
    20.         int ch = edges[i - 2].second;
    21.         if (ch == 0) {
    22.             nodes[fa]->left = nodes[i];
    23.         } else {
    24.             nodes[fa]->right = nodes[i];
    25.         }
    26.     }
    27.     return nodes[1];
    28. }

    29. // 中序遍历收集节点值
    30. void inorder(TreeNode* root, vector<int>& seq) {
    31.     if (!root) return;
    32.     inorder(root->left, seq);
    33.     seq.push_back(root->val);
    34.     inorder(root->right, seq);
    35. }

    36. // 计算最长递增子序列长度
    37. int lengthOfLIS(vector<int>& nums) {
    38.     vector<int> dp;
    39.     for (int num : nums) {
    40.         auto it = lower_bound(dp.begin(), dp.end(), num);
    41.         if (it == dp.end()) {
    42.             dp.push_back(num);
    43.         } else {
    44.             *it = num;
    45.         }
    46.     }
    47.     return dp.size();
    48. }

    49. int main() {
    50.     ios::sync_with_stdio(false);
    51.     cin.tie(nullptr);
    52.    
    53.     int n;
    54.     cin >> n;
    55.    
    56.     vector<int> vals(n);
    57.     for (int i = 0; i < n; ++i) {
    58.         cin >> vals[i];
    59.     }
    60.    
    61.     vector<pair<int, int>> edges(n - 1);
    62.     for (int i = 0; i < n - 1; ++i) {
    63.         cin >> edges[i].first >> edges[i].second;
    64.     }
    65.    
    66.     TreeNode* root = buildTree(n, vals, edges);
    67.     vector<int> seq;
    68.     inorder(root, seq);
    69.    
    70.     int lis_len = lengthOfLIS(seq);
    71.     cout << n - lis_len << endl;
    72.    
    73.     return 0;
    74. }
    复制代码




    五、总结

    通过将问题转化为中序遍历序列的最长递增子序列问题,我们能够高效地计算出将任意二叉树修改为BST所需的最少修改次数。这种方法结合了树遍历和动态规划的思想,展示了算法设计中问题转化的重要性。

    来源:洛谷P3365 改造二叉树:从问题分析到代码实现






    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表