题目 最近公共祖先(暴力版) 有向图的邻接矩阵存储(加强版) 有向图的出度 是否有边
最近公共祖先(暴力版)
题目大意
给定一个从下标为 1 开始的数组,按如下规则构建二叉树:
* 根节点为下标 1;
* 对于任意下标 xxx:
* 左儿子是 2x2x2x;
* 右儿子是 2x+12x+12x+1。
接下来 qqq 次询问,每次给出两个下标,问对应节点在这棵树中的最近公共祖先(LCA,Lowest Common Ancestor)下标。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
题意分析
我们不需要真正建立树,只需要利用节点的下标来推导其父节点即可。
* 由于是完全二叉树模型(数组建树):
* 节点 xxx 的父节点是 ⌊x/2⌋\lfloor x / 2 \rfloor⌊x/2⌋
* 只要将两个节点不断“上跳”,直到相遇,就是它们的最近公共祖先。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
解题思路
对于每次查询:
* 给定两个节点 id1、id2;
* 不断令较大的节点“上跳”到它的父节点(即除以 2),直到 id1 == id2;
* 此时就是最近公共祖先。
这相当于在一棵树上往上跳,最坏情况下跳 logn\log nlogn 层(因为高度约为 log2n\log_2 nlog2 n)。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
时间复杂度分析
* 每次查询最多跳 logn\log nlogn 次;
* 总复杂度:O(q⋅logn)O(q \cdot \log n)O(q⋅logn);
* 对于 q≤105q \leq 10^5q≤105,n≤105n \leq 10^5n≤105 是可以接受的。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
代码演示
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
有向图的邻接矩阵存储(加强版)
题目大意
给定一个包含 NNN 个顶点、MMM 条边的有向图,每条边给出起点、终点和权值。请用邻接矩阵的形式表示该图。
* 邻接矩阵定义为一个 N×NN \times NN×N 的二维数组 g[i][j],其中:
* 如果存在一条从点 iii 指向点 jjj 的有向边,值为对应的权值;
* 否则值为 0。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
输入格式
* 第一行两个整数 N,MN, MN,M,表示顶点数和边数;
* 接下来 MMM 行,每行三个整数 u,v,ku, v, ku,v,k 表示从点 uuu 到点 vvv 有一条权值为 kkk 的边。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
输出格式
* 输出 NNN 行,每行 NNN 个整数,表示邻接矩阵。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
解题思路
我们直接定义一个二维数组 g[N+1][N+1] 初始化为 0。
* 对于每一条边 (u,v,k)(u, v, k)(u,v,k),直接赋值:g[u][v] = k;
* 最后输出邻接矩阵即可。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
时间复杂度
* 空间复杂度:O(N2)O(N^2)O(N2),用于存储邻接矩阵;
* 时间复杂度:O(M+N2)O(M + N^2)O(M+N2),读取 MMM 条边并输出 N×NN \times NN×N 的矩阵。
对 N≤103N \le 10^3N≤103,N2=106N^2 = 10^6N2=106,可以轻松通过。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C++ 代码演示
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
有向图的出度
题目大意
给定一个有向图,包含 NNN 个顶点和 MMM 条有向边。每条边从结点 uuu 指向结点 vvv。
你需要输出从每个点出发的有向边的条数(即每个结点的出度)。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
输入格式
* 第一行输入两个整数 NNN 和 MMM;
* 接下来 MMM 行,每行两个整数 uuu 和 vvv,表示一条从 uuu 到 vvv 的边。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
输出格式
* 输出一行 NNN 个整数,第 iii 个表示结点 iii 的出度。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
解题思路
我们只需要统计每个结点作为起点的边有多少条即可。
操作过程:
1. 初始化一个数组 outDeg[N+1] 全部设为 0;
2. 遍历每条边 (u,v)(u, v)(u,v),令 outDeg[u]++;
3. 最后输出 outDeg[1] ~ outDeg[N]。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
时间复杂度
* 遍历每条边:O(M)O(M)O(M);
* 输出每个点的出度:O(N)O(N)O(N);
* 总时间复杂度:O(N+M)O(N + M)O(N+M),可以通过所有数据。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
代码实现
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
是否有边
解题思路
我们用 vector<node> adj[N+1] 存储每个节点的出边信息。
每个 adj[u] 中存的是所有从 u 出发的边 (v, w),表示存在一条从 u 到 v 权值为 w 的边。
查找方案
* 查找时遍历 adj[x],找到是否有 to == y 的边,有则输出权值,否则输出 0。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
代码演示