diff --git a/畅通工程问题.txt b/畅通工程问题.txt new file mode 100644 index 0000000..3fa0f94 --- /dev/null +++ b/畅通工程问题.txt @@ -0,0 +1,102 @@ +import java.util.Scanner; +import java.util.Set; +import java.util.TreeSet; + + 将城镇抽象为顶点,将有道路联通的城镇划分到同一个集合中,将问题转化成求集合个数的问题 + +public class ChangTongEngine { + + public static void main(String[] args) { + + Scanner scanner = new Scanner(System.in); + while (scanner.hasNextInt()) { + int n = scanner.nextInt(); n表示城镇数量 + if (n == 0) { + break; + } + int m = scanner.nextInt(); m表示道路数目 + + 初始化一个并查集 + UnionFind uf = new UnionFind(n+1); + + for (int i = 0; i m; i++) { + m1和m2表示两个城镇编号 + int m1 = scanner.nextInt(); + int m2 = scanner.nextInt(); + 合并已经建成的城市之间的道路 + uf.union(m1, m2); + + } + TreeSet中元素是有序且不重复的 + TreeSetInteger ts = new TreeSetInteger(); + + for (int i = 1; i = n; i++) { + ts.add(uf.find(i)); + } + + n个节点至少需要n-1条边来连接 + System.out.println(ts.size() - 1); + + } + } +} + +并查集类 +class UnionFind{ + + int[] parent; 记录结点的父亲 + int[] height; 记录树的高度 + + 有参数构造方法 + 初始化并查集 + public UnionFind(int n) { + parent = new int[n]; + height = new int[n]; + for (int i = 0; i parent.length; i++) { + + parent[i] = i; 初始时,每个节点的父亲节点都是自己 + height[i] = 0; 初始时,所有树高均为1 + } + } + + 查操作,找到元素x的根结点 + 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) { + return; + }else { + 按高度合并 + if (height[rootX] height[rootY]) { + parent[rootY] = rootX; + }else if (height[rootX] height[rootY]) { + parent[rootX] = rootY; + }else{ + parent[rootY] = rootX; + 如果高度相同则合并后高度加1 + height[rootX]++; + } + } + + + for (int i = 0; i parent.length; i++) { + if (parent[i] == rootX) { + 遍历并查集中的结点,如果并查集中结点的祖先是x的祖先,则全部设置成y的祖先 + parent[i] = rootY; + } + } + + } +} \ No newline at end of file