DeepSeek LeetCode 3108. 带权图里旅途的最小代价 Java实现
这道题的核心是理解:在一个连通分量内,任意两点之间的最小代价等于所有边权相与的结果。因为我们可以重复走任意边,所以对于两点连通的情况,我们可以通过反复走某些边,把它们的权值按位与起来。
主要思路:
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)
更多推荐




所有评论(0)