列表

详情


2316. 统计无向图中无法互相到达点对数

给你一个整数 n ,表示一张 无向图 中有 n 个节点,编号为 0 到 n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条 无向 边。

请你返回 无法互相到达 的不同 点对数目 。

 

示例 1:

输入:n = 3, edges = [[0,1],[0,2],[1,2]]
输出:0
解释:所有点都能互相到达,意味着没有点对无法互相到达,所以我们返回 0 。

示例 2:

输入:n = 7, edges = [[0,2],[0,5],[2,4],[1,6],[5,4]]
输出:14
解释:总共有 14 个点对互相无法到达:
[[0,1],[0,3],[0,6],[1,2],[1,3],[1,4],[1,5],[2,3],[2,6],[3,4],[3,5],[3,6],[4,6],[5,6]]
所以我们返回 14 。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: long long countPairs(int n, vector<vector<int>>& edges) { } };

javascript 解法, 执行用时: 424 ms, 内存消耗: 110.2 MB, 提交时间: 2023-10-21 07:43:42

/**
 * @param {number} n
 * @param {number[][]} edges
 * @return {number}
 */
var countPairs = function(n, edges) {
    const g = new Array(n).fill(null).map(() => []);
    for (const [x, y] of edges) {
        g[x].push(y);
        g[y].push(x); // 建图
    }

    const vis = new Array(n).fill(false);
    function dfs(x) {
        vis[x] = true; // 避免重复访问同一个点
        let size = 1;
        for (let y of g[x]) {
            if (!vis[y]) {
                size += dfs(y);
            }
        }
        return size;
    }

    let ans = 0, total = 0;
    for (let i = 0; i < n; i++) {
        if (!vis[i]) { // 未访问的点:说明找到了一个新的连通块
            const size = dfs(i);
            ans += size * total;
            total += size;
        }
    }
    return ans;
};

rust 解法, 执行用时: 56 ms, 内存消耗: 20.7 MB, 提交时间: 2023-10-21 07:43:21

impl Solution {
    pub fn count_pairs(n: i32, edges: Vec<Vec<i32>>) -> i64 {
        let n = n as usize;
        let mut g = vec![vec![]; n];
        for e in &edges {
            let x = e[0] as usize;
            let y = e[1] as usize;
            g[x].push(y);
            g[y].push(x); // 建图
        }

        fn dfs(x: usize, g: &Vec<Vec<usize>>, vis: &mut Vec<bool>) -> i32 {
            vis[x] = true; // 避免重复访问同一个点
            let mut size = 1;
            for &y in &g[x] {
                if !vis[y] {
                    size += dfs(y, g, vis);
                }
            }
            size
        }

        let mut ans = 0i64;
        let mut total = 0;
        let mut vis = vec![false; n];
        for i in 0..n {
            if !vis[i] { // 未访问的点:说明找到了一个新的连通块
                let size = dfs(i, &g, &mut vis);
                ans += size as i64 * total as i64;
                total += size;
            }
        }
        ans
    }
}

golang 解法, 执行用时: 264 ms, 内存消耗: 31.2 MB, 提交时间: 2023-10-10 15:35:50

func countPairs(n int, edges [][]int) (ans int64) {
	g := make([][]int, n)
	for _, e := range edges {
		x, y := e[0], e[1]
		g[x] = append(g[x], y)
		g[y] = append(g[y], x)
	}

	vis := make([]bool, n)
	tot, size := 0, 0
	var dfs func(int)
	dfs = func(x int) {
		vis[x] = true
		size++
		for _, y := range g[x] {
			if !vis[y] {
				dfs(y)
			}
		}
	}
	for i, b := range vis {
		if !b {
			size = 0
			dfs(i)
			ans += int64(size) * int64(tot)
			tot += size
		}
	}
	return
}

cpp 解法, 执行用时: 548 ms, 内存消耗: 190.5 MB, 提交时间: 2023-10-10 15:35:32

class Solution {
public:
    long long countPairs(int n, vector<vector<int>> &edges) {
        vector<vector<int>> g(n);
        for (auto &e : edges) {
            int x = e[0], y = e[1];
            g[x].push_back(y);
            g[y].push_back(x);
        }

        bool vis[n]; memset(vis, 0, sizeof(vis));
        long ans = 0L;
        int cnt = 0;
        function<void(int)> dfs = [&](int x) {
            vis[x] = true;
            ++cnt;
            for (int y: g[x]) if (!vis[y]) dfs(y);
        };
        for (int i = 0, tot = 0; i < n; ++i)
            if (!vis[i]) {
                cnt = 0;
                dfs(i);
                ans += (long) cnt * tot;
                tot += cnt;
            }
        return ans;
    }
};

java 解法, 执行用时: 48 ms, 内存消耗: 108.2 MB, 提交时间: 2023-10-10 15:35:17

class Solution {
    List<Integer>[] g;
    boolean[] vis;
    int cnt;

    public long countPairs(int n, int[][] edges) {
        g = new ArrayList[n];
        Arrays.setAll(g, e -> new ArrayList<>());
        for (var e : edges) {
            int x = e[0], y = e[1];
            g[x].add(y);
            g[y].add(x);
        }
        vis = new boolean[n];
        var ans = 0L;
        for (int i = 0, tot = 0; i < n; ++i)
            if (!vis[i]) {
                cnt = 0;
                dfs(i);
                ans += (long) cnt * tot;
                tot += cnt;
            }
        return ans;
    }

    void dfs(int x) {
        vis[x] = true;
        ++cnt;
        for (var y : g[x]) if (!vis[y]) dfs(y);
    }
}

python3 解法, 执行用时: 716 ms, 内存消耗: 62.5 MB, 提交时间: 2023-10-10 15:35:02

class UnionFindSet:
    def __init__(self, n: int) -> None:
        self.parent = [i for i in range(n)]
        self.rank =[0 for _ in range(n)]
        
    def find(self, x: int) -> int:
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
        
    def union(self, x: int, y: int) -> None:
        xroot, yroot = self.find(x), self.find(y)
        if xroot != yroot:
            if self.rank[xroot] < self.rank[yroot]:
                xroot, yroot = yroot, xroot
            self.parent[yroot] = xroot
            if self.rank[xroot] == self.rank[yroot]:
                self.rank[xroot] += 1
                

class Solution:
    def countPairs(self, n: int, edges: List[List[int]]) -> int:
        ufs = UnionFindSet(n)
        for u, v in edges:
            ufs.union(u, v)
                
        counter = defaultdict(int)
        for i in range(n):
            counter[ufs.find(i)] += 1
        
        res = 0
        for cnt in counter.values():
            res += cnt * (n - cnt)

        return res // 2

python3 解法, 执行用时: 560 ms, 内存消耗: 86.5 MB, 提交时间: 2023-10-10 15:34:36

class Solution:
    # bfs
    def countPairs(self, n: int, edges: List[List[int]]) -> int:
        graph = defaultdict(set)
        for u, v in edges:
            graph[u].add(v)
            graph[v].add(u)
            
        visited = [False for _ in range(n)]
        cc = 0
        cc2nodes = defaultdict(set)

        for i in range(n):
            if not visited[i]:
                cc += 1
                que = deque()
                que.append(i)
                while que:
                    u = que.popleft()
                    if u not in cc2nodes[cc]:
                        cc2nodes[cc].add(u)
                    
                    for v in graph[u]:
                        if not visited[v]:
                            visited[v] = True
                            que.append(v)

        cnts = map(len, cc2nodes.values())
        res = 0
        for cnt in cnts:
            res += cnt * (n - cnt)
        
        return res // 2

python3 解法, 执行用时: 448 ms, 内存消耗: 104.3 MB, 提交时间: 2023-10-10 15:33:00

'''
dfs 求连通块的大小

建图后,用 DFS 可以求出每个连通块的大小。
求连通块的大小的同时,用一个变量 tot 维护前面求出的连通块的大小之和。
设当前连通块的大小为 size,那么它对答案的贡献就是 size⋅tot。
累加所有贡献,即为答案。
'''
class Solution:
    def countPairs(self, n: int, edges: List[List[int]]) -> int:
        g = [[] for _ in range(n)]
        for x, y in edges:
            g[x].append(y)
            g[y].append(x)

        vis, ans, tot, size = [False] * n, 0, 0, 0
        def dfs(x: int) -> None:
            nonlocal size
            vis[x] = True
            size += 1
            for y in g[x]:
                if not vis[y]:
                    dfs(y)
        for i in range(n):
            if not vis[i]:
                size = 0
                dfs(i)
                ans += size * tot
                tot += size
        return ans

上一题