题目地址:
给定一个 n个节点的无向图,以邻接矩阵给出。每个节点代表一个网络中的节点。再给定一个数组A,A[i]表示节点i ii被感染了(下文称A里的点是”感染源“)。当一个节点被感染了,它所在的连通块的所有节点都会被感染。现在允许选取一个“感染源”,将其变为”未感染“。问将哪个节点变为”未感染“可以使得剩余节点的总的被感染节点数量最小。如果有多个答案,则返回编号最小的节点。
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Solution {
class UnionFind {
int[] parent, size;
public UnionFind(int size) {
parent = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = i;
}
this.size = new int[size];
Arrays.fill(this.size, 1);
}
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public void union(int x, int y) {
int px = find(x), py = find(y);
if (px == py) {
return;
}
parent[px] = py;
size[py] += size[px];
}
}
public int minMalwareSpread(int[][] graph, int[] initial) {
int n = graph.length;
UnionFind uf = new UnionFind(n);
// 矩阵是对称的,所以只需要遍历右上半部分就可以了
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (graph[i][j] == 1) {
uf.union(i, j);
}
}
}
// 用map存一下每个被感染的连通块里,”感染源“的个数
Map<Integer, Integer> map = new HashMap<>();
for (int x : initial) {
int px = uf.find(x);
map.put(px, map.getOrDefault(px, 0) + 1);
}
// maxN存被感染的最大连通块的size
int maxN = 0, res = -1;
for (int x : initial) {
int px = uf.find(x);
// 如果找到了感染源数是1的连通块,那么就挑一个size最大的连通块
if (map.get(px) == 1) {
if (uf.size[px] > maxN) {
maxN = uf.size[px];
res = x;
} else if (uf.size[px] == maxN) {
// 如果有多个感染源数是1的连通块size一样,
// 则按照要求要返回编号最小的感染源头节点
res = Math.min(res, x);
}
}
}
// 如果每个连通块的感染源都多于1,那就清洁initial里编号最小的节点
if (res == -1) {
res = n;
for (int x : initial) {
res = Math.min(res, x);
}
}
return res;
}
}
参考链接: