当前位置:首页 > 洛谷 > 洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

6个月前 (06-14)

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析  异或路径 Trie树 图论算法 动态规划 第1张

一、题目解读

洛谷P4551题要求在一个无向图中,寻找任意两点路径权值异或后的最大值。题目输入为的边信息(点数n和n-1条边),每条边包含起点、终点及权值。需输出所有路径中权值异或的最大值。问题核心在于高效计算任意两点路径的异或和,并找到最大值。

二、解题思路

采用“预处理+Trie树查询”策略:

    1. DFS预处理:通过深度优先搜索(DFS)遍历图,计算每个节点到根节点(默认为1)的路径权值异或和,存储于d数组

    2. Trie优化:将d数组中的每个值插入Trie树(二进制字典树),查询时利用Trie树特性,优先选择与当前位相反的子节点,以最大化异或结果。

    3. 贪心思想:每次查询时,从高位到低位遍历,若存在相反位分支,则选择该分支,确保异或值尽可能大。

三、解题步骤

1. 建图:使用邻接表存储无向图,边信息包含终点和权值。

2. 预处理异或路径:从根节点开始DFS,递归计算每个节点到根的异或值d[i] = d[父节点] ^ 边权值。

3. 构建Trie树:将d数组元素逐位插入Trie树,每个节点维护0/1子节点指针

4. 查询最大值:对每个d[i],在Trie树中从高位到低位遍历,若当前位相反分支存在,则转向该分支,累加贡献值,最终得到最大异或值。

5. 更新答案:遍历所有节点的查询结果,取最大值输出。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 1e5 + 5; // 最大点数
const int BIT = 30; // 二进制位数

// 边结构
struct Edge {
    int to, w;
};
vector<Edge> G[MAXN]; // 邻接表

int trie[MAXN * BIT][2], cnt = 1; // Trie树,cnt为节点计数器
int d[MAXN]; // 节点到根的异或路径值

// 预处理异或路径(DFS)
void dfs(int u, int fa) {
    for (auto &e : G[u]) { // 遍历u的所有邻接边
        if (e.to == fa) continue; // 跳过父节点
        d[e.to] = d[u] ^ e.w; // 更新子节点的异或值
        dfs(e.to, u); // 递归处理子树
    }
}

// 向Trie树插入数字x
void insert(int x) {
    int p = 1; // 从根节点开始
    for (int i = BIT; i >= 0; i--) { // 从最高位到最低位
        int b = (x >> i) & 1; // 获取当前位
        if (!trie[p][b]) trie[p][b] = ++cnt; // 若子节点不存在,创建新节点
        p = trie[p][b]; // 移动到子节点
    }
}

// 查询与x异或最大的值
int query(int x) {
    int p = 1, res = 0; // 从根节点开始,结果初始化
    for (int i = BIT; i >= 0; i--) {
        int b = (x >> i) & 1; // 当前位
        if (trie[p][!b]) { // 若相反位分支存在
            res += (1 << i); // 累加贡献值
            p = trie[p][!b]; // 转向相反分支
        } else {
            p = trie[p][b]; // 否则沿原分支
        }
    }
    return res;
}

int main() {
    int n;
    cin >> n; // 输入点数
    for (int i = 1; i < n; i++) { // 输入n-1条边
        int u, v, w;
        cin >> u >> v >> w;
        G[u].push_back({v, w}); // 双向建边
        G[v].push_back({u, w});
    }
    
    dfs(1, 0); // 从根节点1开始预处理

    int ans = 0;
    for (int i = 1; i <= n; i++) {
        insert(d[i]); // 插入到Trie树
        ans = max(ans, query(d[i])); // 更新最大异或值
    }
    
    cout << ans << endl; // 输出结果
    return 0;
}

五、总结

本解法巧妙结合图论预处理与Trie树查询,将路径异或问题转化为二进制位匹配问题。通过预处理计算节点到根的异或值,利用Trie树高效查找最大异或值,时间复杂度为O(nlogn)。该算法对处理大规模异或路径问题具有借鉴意义,尤其适用于需要快速查找异或极值的场景。

原创内容 转载请注明出处

分享给朋友:

相关文章

力扣740.删除并获得点数 预处理与动态规划的巧妙融合

力扣740.删除并获得点数 预处理与动态规划的巧妙融合

题意解析:给定一组数字,每当你选择一个数字x时,所有等于x-1和x+1的数字都会被自动移除。你需要通过巧妙的选择顺序,最大化获得的点数总和。这个问题可以转化为对离散化数字分布的动态规划问题——将相邻数...

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

题目重解我们面对一个经典背包问题的变体:给定n个物品,每个物品有重量w和价值v,背包容量为V。需要回答两个问题:1) 普通情况下能获得的最大价值;2) 必须恰好装满背包时的最大价值(若无法装满则输出0...

NOIP2005 普及组 洛谷P1408 背包问题的空间优化技巧与实战应用

NOIP2005 普及组 洛谷P1408 背包问题的空间优化技巧与实战应用

题目重解想象你是一名药师,有t分钟在山上采集m种草药。每种草药需要time分钟采集,价值为num。这就像考试时分配时间做题,要选择收益最大的题目组合。题目要求计算在规定时间内能获得的最大草药价值。解题...

IOI 1994 洛谷1216:如何用O(1)空间解决数字三角形问题?附代码实现

IOI 1994 洛谷1216:如何用O(1)空间解决数字三角形问题?附代码实现

题目重解:数字三角形是一个经典的动态规划问题,给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们需要找到一条路径,使得路径上经过的数字总和最大。这个问题可以很...

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

一、题目解读2019年CSP-J的“纪念品”问题(对应洛谷P5662)要求玩家在T天内通过买卖纪念品最大化金币收益。每天可交易N种商品,需计算最优策略下的最终金币数。题目强调动态规划思维与资源分配优化...

手搓邻接矩阵类代码注释与实现指南:从零开始理解图论数据结构(适合小白)

一、简介和特点邻接矩阵是用于表示图(Graph)的一种数据结构,通常用二维数组存储节点之间的关系。本文的graph类通过C++实现了一个基础的邻接矩阵结构,特点如下:1. 动态创建:根据用户输入的节点...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。