这道题的核心是理解:在一个连通分量内,任意两点之间的最小代价等于所有边权相与的结果。因为我们可以重复走任意边,所以对于两点连通的情况,我们可以通过反复走某些边,把它们的权值按位与起来。

主要思路:

1. 先找出所有连通分量(可以用并查集)
2. 对每个连通分量,计算分量内所有边权的按位与结果,记为 componentAnd
3. 对于每个查询 (u, v):
   · 如果 u 和 v 不连通,返回 -1
   · 如果 u == v,返回 0
   · 否则返回 componentAnd

```java
class Solution {
    public int[] minimumCost(int n, int[][] edges, int[][] query) {
        // 并查集初始化
        UnionFind uf = new UnionFind(n);
        
        // 第一步:建立连通关系
        for (int[] edge : edges) {
            uf.union(edge[0], edge[1]);
        }
        
        // 第二步:计算每个连通分量的边权 AND 值
        // 初始化为 -1(二进制全1),因为 -1 & x = x
        int[] componentAnd = new int[n];
        for (int i = 0; i < n; i++) {
            componentAnd[i] = -1; // 全1
        }
        
        for (int[] edge : edges) {
            int root = uf.find(edge[0]);
            componentAnd[root] &= edge[2];
        }
        
        // 第三步:处理查询
        int[] ans = new int[query.length];
        for (int i = 0; i < query.length; i++) {
            int u = query[i][0];
            int v = query[i][1];
            
            if (u == v) {
                ans[i] = 0;
                continue;
            }
            
            int rootU = uf.find(u);
            int rootV = uf.find(v);
            
            if (rootU != rootV) {
                ans[i] = -1;
            } else {
                ans[i] = componentAnd[rootU];
            }
        }
        
        return ans;
    }
    
    // 并查集实现
    class UnionFind {
        int[] parent;
        int[] rank;
        
        UnionFind(int n) {
            parent = new int[n];
            rank = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }
        
        int find(int x) {
            if (parent[x] != x) {
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }
        
        void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX == rootY) return;
            
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            } else if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            } else {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
        }
    }
}
```

核心原理:

· 设连通分量内边权为 w1, w2, ..., wk
· 由于可以重复走边,从 u 到 v 的代价可以取任意路径上所有边权的 AND
· 要达到最小化,我们可以走一个包含所有边的环(边可以重复),这样代价 = w1 & w2 & ... & wk
· 因为 AND 操作满足:重复走同一条边不会改变结果(x & x = x),且 AND 结果一定不大于任意子集的 AND

复杂度:

· 时间:O(n + m + q·α(n)),其中 m 是边数,q 是查询数
· 空间:O(n)

 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐