测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 注意:两个城市之间可以有多条道路相通,也就是说 3 3 1 2 1 2 2 1 这种输入也是合法的 当N为0时,输入结束,该用例不被处理。
对每个测试用例,在1行里输出最少还需要建设的道路数目。
4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0
1 0 2 998
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N;
while (scanner.hasNext() && (N = scanner.nextInt()) != 0) {
int M = scanner.nextInt();
UnionFindSet ufs = new UnionFindSet(N, 1000);
for (int i = 0; i < M; i++) {
ufs.union(scanner.nextInt(), scanner.nextInt());
}
int count = -1;
for (int i = 1; i <= N; i++) {
if (ufs.father[i] == i) {
count++;
}
}
System.out.println(count);
}
}
public static class UnionFindSet {
private int father[];
private int height[];
public UnionFindSet(int n, int max) {
this.father = new int[max];
this.height = new int[max];
for (int i = 1; i <= n; i++) {
this.father[i] = i;
this.height[i] = 0;
}
}
int find(int x) {
if (x != father[x]) {
father[x] = find(father[x]);
}
return father[x];
}
void union(int x, int y) {
x = find(x);
y = find(y);
if (x != y) {
if (height[x] < height[y]) {
father[x] = y;
} else if (height[x] > height[y]) {
father[y] = x;
} else {
father[y] = x;
height[x]++;
}
}
}
}
} import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int[] parent = new int[1000];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s;
while ((s = br.readLine()) != null) {
if (s.equals("0")) break;
String[] ss = s.split(" ");
int n = Integer.parseInt(ss[0]);//n 城镇
int m = Integer.parseInt(ss[1]);//m 道路
for (int i = 1; i <= n; i++) { //初始化父节点
parent[i] = -1;
}
for (int i = 0; i < m; i++) { //依次对每条路进行操作
String[] str = br.readLine().split(" ");
int x = Integer.parseInt(str[0]);
int y = Integer.parseInt(str[1]);
x = FindRoot(x);
y = FindRoot(y);
if (x != y) { //两个点不属于一个集合,则连起来
parent[x] = y;
}
}
int count = 0; //找出此时有多少根节点,即多少个集合
for (int i = 1; i <= n; i++) {
if (parent[i] == -1) count++;
}
System.out.println(--count);
}
}
public static int FindRoot(int t) {
if (parent[t] == -1) return t;
else {
int r = FindRoot(parent[t]);
parent[t] = r; // 路径压缩
return r;
}
}
}
import java.util.Scanner;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
int townNum = scanner.nextInt();
int pathNum = scanner.nextInt();
UnionFind unionFind = new UnionFind(townNum+1);
for (int i = 0; i < pathNum; i++) {
int town1 = scanner.nextInt();
int town2 = scanner.nextInt();
unionFind.union(town1,town2);
}
TreeSet<Integer> set = new TreeSet<>();
for (int i = 1; i <=townNum; i++) {
set.add(unionFind.find(i));
}
System.out.println(set.size()-1);
}
}
public static class UnionFind {
private int[] id;
public UnionFind(int N) {
id = new int[N];
for(int i = 0; i < N; i++) id[i] = i;
}
public int find(int p) {
return id[p];
}
public void union(int p, int q){
int pRoot = find(p);
int qRoot = find(q);
if(pRoot == qRoot) return;
for(int i = 0; i < id.length; i++)
if(id[i] == pRoot) id[i] = qRoot;
}
}
}