We have a network of computers and a list of bi-directional connections. Each of these connections allows a file transfer from one computer to another. Is it possible to send a file from any computer on the network to any other?
Each input file contains one test case. For each test case, the first line contains N (2≤N≤104), the total number of computers in a network. Each computer in the network is then represented by a positive integer between 1 and N. Then in the following lines, the input is given in the format:
I c1 c2
where I
stands for inputting a connection between c1
and c2
; or
C c1 c2
where C
stands for checking if it is possible to transfer files between c1
and c2
; or
S
where S
stands for stopping this case.
For each C
case, print in one line the word "yes" or "no" if it is possible or impossible to transfer files between c1
and c2
, respectively. At the end of each case, print in one line "The network is connected." if there is a path between any pair of computers; or "There are k
components." where k
is the number of connected components in this network.
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S
no
no
yes
There are 2 components.
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S
no
no
yes
yes
The network is connected.
先给一个正整数N,表示的电脑编号从1~N,然后给出三种操作:检查两台电脑有没有连接,连接两台电脑,结束,最后还要看这1~ N台电脑连成了几个局域网,如果全部连接就打印全部连接,否则就打印有几个局域网
考察并查集,用类似树的思想构建,不过Set[i]表示序号为i的节点的根节点,而根节点的绝对值则表示这个集合里有多少节点,每个集合只有一个根节点,
并的操作是将小集合往大集合里面并,小集合根节点的值修改为大集合的根节点下标,大集合根节点加上小集合根节点里的值
查的操作利用了路径压缩,如果当前节点是根节点,直接返回,否则就以当前节点递归查找并返回查找到的值
题目中集合下标是从1开始,初始化集合要从1开始
/*
集合初始化
检查两台电脑有没有连接就是看他们集合根节点相不相同
连接两台电脑就是将它们各自归属的集合合并,小的往大的里面合并
看这1~N台电脑连成了几个局域网就是找有几个根节点
利用路径压缩,查找时将集合树变矮
*/
#include
#include
#define MAX_SIZE 100005
#define CHECK 'C'
#define INPUT 'I'
#define STOP 'S'
int Set[MAX_SIZE]; //Set[i]的含义是下标为i的节点的父节点
int FindRoot(int data) { //查找data所在集合根节点
if(Set[data] < 0) { //Set[data]的值是-1说明data就是根节点
return data;
}
else {
return Set[data] = FindRoot(Set[data]); //路径压缩,直接连接到根节点并返回根节点
}
}
void Connect(int a, int b) { //connect函数实际上是集合的并预算
int roota = FindRoot(a);
int rootb = FindRoot(b);
if(abs(Set[roota]) >= abs(Set[rootb])) { //为了避免树太高,将小集合往大集合里面并
Set[roota] += Set[rootb]; //根节点里保存的绝对值是这个集合里节点的数量
Set[rootb] = roota;
}
else {
Set[rootb] += Set[roota];
Set[roota] = rootb;
}
return;
}
int Exam(int a, int b) {
int roota = FindRoot(a);
int rootb = FindRoot(b);
if(roota == rootb) {
return 1;
}
else {
return 0;
}
}
void Count(int nodeNum) {
int num = 0;
for(int i = 1; i <= nodeNum; i++) {
if(Set[i] < 0) {
num++;
}
}
if(num == 1) {
printf("The network is connected.");
}
else {
printf("There are %d components.", num);
}
return;
}
int main() {
int N;
scanf("%d", &N);
getchar();
for(int i = 1; i <= N; i++) {
Set[i] = -1;
}
char operation;
while(scanf("%c", &operation) && operation != STOP) {
int a, b;
scanf("%d %d", &a, &b);
getchar();
int flag = 0;
switch (operation) {
case INPUT:
Connect(a, b);
break;
case CHECK: {
flag = Exam(a, b);
if(flag) {
printf("yes\n");
}
else {
printf("no\n");
}
break;
}
}
}
Count(N);
return 0;
}