当前位置:首页 > 力扣 > 【力扣2846题】图论+二进制提升:高效解决连通性问题(附C++代码)

【力扣2846题】图论+二进制提升:高效解决连通性问题(附C++代码)

2天前

【力扣2846题】图论+二进制提升:高效解决连通性问题(附C++代码) 力扣题解 图论算法 二进制 LCA算法 邻接表 第1张

一、题目解读

力扣2846题要求解决一个基于连通性的操作优化问题。给定一个无向图,包含边权重,以及一系列查询,每个查询询问两点间路径的最小操作次数。题目关键在于高效计算路径上权重分布的统计信息,并转化为操作次数。难点在于处理大量查询时的效率优化,需借助图论算法数据结构压缩时间复杂度

二、解题思路

解题思路围绕三个核心:图结构预处理、LCA(最近公共祖先)计算和路径权重统计优化。

1. 图结构预处理:使用邻接表存储边信息,通过DFS遍历记录节点深度及父节点关系,为后续LCA计算做准备。

2. 二进制提升优化LCA:构建父节点表的二进制层次结构,通过位运算快速跳跃至公共祖先,降低查询时间。

3. 路径权重统计:维护每个节点到根的权重计数数组,利用LCA结果合并路径上的权重分布,通过差值计算操作次数。

三、解题步骤

1. 初始化数据结构:创建邻接表adj、父节点表parent、深度depth及权重计数数组cnt。

2. 构建图与预处理:

○ 通过edges构建邻接表,双向存储边信息(节点+权重)。

○ 执行dfs(u, p, d)递归,初始化深度、父节点,并继承父节点的权重计数。

3. 二进制提升预处理:通过位运算生成父节点表的更高层次,支持快速LCA查询。

4. 处理查询:

○ 对每个查询(u, v),通过LCA找到公共祖先lca。

○ 合并u、v到lca路径的权重计数,计算总权重和最大权重,差值即为操作次数。

四、代码与注释

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

class Solution {
    vector<vector<pair<int, int>>> adj; // 邻接表:{节点, 边权}
    vector<vector<int>> parent;         // 二进制提升父节点表
    vector<int> depth;                  // 节点深度
    vector<array<int, 27>> cnt;         // 节点到根的各权重计数
    
public:
    vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
        // 初始化
        adj.resize(n);
        parent.assign(n, vector<int>(20, -1));
        depth.resize(n);
        cnt.resize(n);
        for(auto& e : edges) {
            adj[e[0]].emplace_back(e[1], e[2]);
            adj[e[1]].emplace_back(e[0], e[2]);
        }
        
        // DFS预处理
        dfs(0, -1, 0);
        
        // 二进制提升预处理
        for(int k = 1; k < 20; ++k) {
            for(int u = 0; u < n; ++u) {
                if(parent[u][k-1] != -1) {
                    parent[u][k] = parent[parent[u][k-1]][k-1];
                }
            }
        }
        
        // 处理查询
        vector<int> res;
        for(auto& q : queries) {
            int u = q[0], v = q[1];
            int l = lca(u, v);
            
            // 合并路径上的权重计数
            array<int, 27> total{};
            for(int i = 1; i <= 26; ++i) {
                total[i] = cnt[u][i] + cnt[v][i] - 2 * cnt[l][i];
            }
            
            // 计算操作次数
            int sum = 0, max_cnt = 0;
            for(int i = 1; i <= 26; ++i) {
                sum += total[i];
                max_cnt = max(max_cnt, total[i]);
            }
            res.push_back(sum - max_cnt);
        }
        return res;
    }
    
private:
    void dfs(int u, int p, int d) {
        parent[u][0] = p;
        depth[u] = d;
        if(p != -1) {
            // 继承父节点的计数
            cnt[u] = cnt[p];
            // 更新当前边的权重计数
            for(auto& [v, w] : adj[u]) {
                if(v == p) {
                    cnt[u][w]++;
                    break;
                }
            }
        }
        // 递归处理子节点
        for(auto& [v, w] : adj[u]) {
            if(v != p) dfs(v, u, d+1);
        }
    }
    
    int lca(int u, int v) {
        // 确保u是较深的节点
        if(depth[u] < depth[v]) swap(u, v);
        // 提升u到与v同深度
        for(int k = 19; k >= 0; --k) {
            if(depth[u] - (1 << k) >= depth[v]) {
                u = parent[u][k];
            }
        }
        if(u == v) return u;
        // 同时提升u和v
        for(int k = 19; k >= 0; --k) {
            if(parent[u][k] != -1 && parent[u][k] != parent[v][k]) {
                u = parent[u][k];
                v = parent[v][k];
            }
        }
        return parent[u][0];
    }
};

注释说明:

● adj:邻接表,存储边信息(节点+权重)。

● parent:二进制提升表,通过层次关系快速查找LCA。

● cnt:节点到根的各权重计数,用于路径统计。

● dfs递归函数:初始化深度、父节点及继承权重计数。

● lca(u, v)(代码中未显示,需补充):通过二进制提升计算公共祖先。

五、总结

本解法通过图论预处理与二进制提升技术,将LCA查询时间复杂度优化至O(logN),结合路径权重差值的巧妙计算,避免了对路径的重复遍历。核心在于利用空间换时间:父节点表和权重计数数组大幅降低单次查询成本。适用于处理大量连通性查询的场景,为同类问题提供高效解决范式。

原创内容 转载请注明出处

分享给朋友:

相关文章

【深度优先搜索实战】力扣547题:省份数量问题的图论解法

【深度优先搜索实战】力扣547题:省份数量问题的图论解法

题目解读‌我们面对的是一个典型的图论问题:给定一个城市的连接矩阵,需要计算其中相互连通的城市群(省份)数量。这个问题可以抽象为无向图中的连通分量计算,每个城市代表图中的一个节点,城市之间的连接关系代表...

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

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

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

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

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

洛谷1111题解题全解析:基于Kruskal算法与并查集的最小生成树实现

洛谷1111题解题全解析:基于Kruskal算法与并查集的最小生成树实现

一、题目解读洛谷1111题是一道经典的图论问题,要求构建一个无向图的最小生成树,并输出其最大边权值。题目核心在于通过给定的边集合,找到连接所有节点的最小权值子集,同时保证无环。这通常涉及最小生成树算法...

牛客13279题解:利用递归与深度优先搜索计算树的最大高度(附完整代码)

牛客13279题解:利用递归与深度优先搜索计算树的最大高度(附完整代码)

一、题目解读牛客13279题要求计算给定树的最大高度。题目输入一棵以邻接表形式表示的树(节点从0开始编号),需要输出从根节点到最深叶节点的最长路径长度。树的结构由n个节点和n-1条边构成,保证为连通无...

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

一、题目解读力扣3112题要求解决带时间限制的最短路径问题:给定一个有向图,节点具有消失时间,需计算从起点到各节点的最短路径,且路径总时间不能超过节点的消失时间。题目难点在于需在传统最短路径算法(如D...

发表评论

访客

看不清,换一张

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