赞
踩
Leetcode.2867 统计树中的合法路径数目
rating : 2428
给你一棵 n n n 个节点的无向树,节点编号为 1 1 1 到 n n n 。给你一个整数 n n n 和一个长度为 n − 1 n - 1 n−1 的二维整数数组 e d g e s edges edges ,其中 e d g e s [ i ] = [ u i , v i ] edges[i] = [u_i, v_i] edges[i]=[ui,vi] 表示节点 u i u_i ui 和 v i v_i vi 在树中有一条边。
请你返回树中的 合法路径数目 。
如果在节点 a a a 到节点 b b b 之间 恰好有一个 节点的编号是质数,那么我们称路径 ( a , b ) (a, b) (a,b) 是 合法的 。
注意:
输入:n = 5, edges = [[1,2],[1,3],[2,4],[2,5]]
输出:4
解释:恰好有一个质数编号的节点路径有:
- (1, 2) 因为路径 1 到 2 只包含一个质数 2 。
- (1, 3) 因为路径 1 到 3 只包含一个质数 3 。
- (1, 4) 因为路径 1 到 4 只包含一个质数 2 。
- (2, 4) 因为路径 2 到 4 只包含一个质数 2 。
只有 4 条合法路径。
输入:n = 6, edges = [[1,2],[1,3],[2,4],[3,5],[3,6]]
输出:6
解释:恰好有一个质数编号的节点路径有:
- (1, 2) 因为路径 1 到 2 只包含一个质数 2 。
- (1, 3) 因为路径 1 到 3 只包含一个质数 3 。
- (1, 4) 因为路径 1 到 4 只包含一个质数 2 。
- (1, 6) 因为路径 1 到 6 只包含一个质数 3 。
- (2, 4) 因为路径 2 到 4 只包含一个质数 2 。
- (3, 6) 因为路径 3 到 6 只包含一个质数 3 。
只有 6 条合法路径。
我们先将 [ 1 , 1 0 5 ] [1,10^5] [1,105] 内的质数筛出来,用 n p np np 记录。如果 n p [ x ] = t r u e np[x] = true np[x]=true,说明 x x x 不是质数;否则是质数。
我们可以从 质数点 x x x 出发,开始 dfs,访问非质数点,因为一条 合法路径 只存在一个质数点。
通过上述操作,可以将 x x x 连接的几个 非质数连通块 计算出来。
假设如上图,通过 x x x 分割出了三个 非质数连通块 ,每个连通块中的节点数量分别为 2 , 3 , 4 2,3,4 2,3,4。
我们现在来计算 合法路径数量(从左到右计算,保证不重不漏):
上图通过 x x x 的合法路径条数为 6 + 20 + 9 = 35 6 + 20 + 9 = 35 6+20+9=35。
我们可以用一个数组 s z sz sz,记录下已经计算过的连通块数量。假设 1 1 1 号连通块中的两个节点分别为 i , j i , j i,j,那么 s z [ i ] = s z [ j ] = 2 sz[i] = sz[j] = 2 sz[i]=sz[j]=2。
如果下一次有另外一个 质数点 y y y 和这个 1 1 1号连通块 相连,那么我们就可以直接计算,不用再次遍历记录连通块节点的数量。
时间复杂度: O ( n ) O(n) O(n)
C++代码:
using LL = long long; const int MX = 1e5; bool np[MX + 1]; auto init = []() ->int{ np[1] = true; for(int i = 2;i * i <= MX;i++){ if(!np[i]){ for(int j = i * i;j <= MX;j += i) np[j] = true; } } return 0; }(); class Solution { public: long long countPaths(int n, vector<vector<int>>& edges) { vector<vector<int>> g(n + 1); for(auto &e:edges){ auto a = e[0] , b = e[1]; g[a].push_back(b); g[b].push_back(a); } vector<int> sz(n + 1); vector<int> nodes; function<void(int,int)> dfs = [&](int x,int fa) ->void{ nodes.push_back(x); for(auto y:g[x]){ if(y == fa || !np[y]) continue; dfs(y,x); } }; LL ans = 0; for(int x = 1;x <= n;x++){ if(np[x]) continue; //合数就跳过 , 是以质数为起点dfs LL sum = 0; for(auto y : g[x]){ //接着要求的是合数的连通块 if(!np[y]) continue; //如果这个连通块没有被计算过,就计算 if(sz[y] == 0){ nodes.clear(); dfs(y,-1); for(auto node:nodes) sz[node] = nodes.size(); } ans += sum * sz[y]; sum += sz[y]; } ans += sum; } return ans; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。