夺回据点
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 577 ms, 内存: 67.6 MB
/*
* 思路:
* 1. 找出最低成本的据点作为初始夺回的据点。
* 2. 使用一个并查集(Union-Find)结构来维护已夺回和未夺回据点的连通性。
* 3. 从最小花费开始尝试夺回据点,确保每次夺回据点后,剩余的魔物据点依然连通。
*/
import java.util.*;
import java.util.stream.Collectors;
public class Solution {
public int minCost(int[] cost, int[][] roads) {
int n = cost.length;
UnionFind uf = new UnionFind(n);
List<int[]> edges = Arrays.stream(roads)
.sorted(Comparator.comparingInt(o -> Math.min(cost[o[0]], cost[o[1]])))
.collect(Collectors.toList());
int minCost = Integer.MAX_VALUE;
for (int[] edge : edges) {
int u = edge[0];
int v = edge[1];
if (!uf.connected(u, v)) {
uf.union(u, v);
minCost = Math.min(minCost, cost[u] + cost[v]);
}
}
return minCost;
}
class UnionFind {
private int[] parent;
private int[] rank;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 1;
}
}
public int find(int x) {
if (x != parent[x]) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else {
parent[rootY] = rootX;
rank[rootX]++;
}
}
}
public boolean connected(int x, int y) {
return find(x) == find(y);
}
}
}
解释
方法:
本题解采用了基于深度优先搜索(DFS)的点双连通分量(Biconnected Components)的算法来解决问题。每个点双连通分量是一个最大的子图,其中任何两个顶点都有两条不相交的路径相连,这样即使去掉任何一个节点,其余节点依然连通。算法的主要步骤如下:1. 使用DFS遍历图,同时记录每个节点的访问序号dfn和最小可回溯到的祖先节点序号low。2. 利用dfn和low值,判断并记录割点(关键节点,其移除会导致图的不连通)。3. 构建每个点双连通分量,每遇到一个新的割点或遍历完一个连通分量时,将该分量的节点记录下来。4. 对每个点双连通分量,找到非割点的最小成本,以此计算最小的资源消耗。5. 特殊处理单个割点和非割点情况下的最小成本计算。整体思路是通过图的深度优先遍历确定关键节点和连通分量,然后基于每个连通分量的成本最小化总资源消耗。
时间复杂度:
O(V + E)
空间复杂度:
O(V + E)
代码细节讲解
🦆
在DFS过程中,`dfn[u] <= low[v]`条件是如何确定节点u是否为割点的?请解释其背后的逻辑。
▷🦆
在处理点双连通分量时,为什么只考虑非割点的最小成本?割点的成本是否应该也考虑在内?
▷🦆
算法中提到,如果一个点双连通分量中只有一个割点,就使用那个分量的最小成本。这种方法是否能确保总成本最小?存在没有割点的分量该如何处理?
▷