题目要求:
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 betweenc1
andc2
, 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 arek
components." wherek
is the number of connected components in this network.
样例输入1:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S
样例输出1:
no
no
yes
There are 2 components.
样例输入2:
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
样例输出2 :
no
no
yes
yes
The network is connected.
题解:
思路如注释所示,可通过所有测试点。
#include<bits/stdc++.h>
using namespace std;
#define MaxSize 10005
typedef int ElementType;
typedef int SetName;
typedef ElementType SetType[MaxSize];
void Init(SetType S,int n){
for(int i=0;i<n;i++) S[i] = -1;
return;
}
void Union(SetType S,int Root1,int Root2){
if(abs(S[Root2])>abs(S[Root1])) //比较二者树高的绝对值,树二比较高
S[Root1] = Root2; //把树一合并到树二上,不会导致树高度的增加
else{
if(S[Root2] == S[Root1]) S[Root1]--; //因为这里把树的高度计为负值存储在根节点所以高度+1为负数的减一
S[Root2] = Root1;
}
}
int Find(SetType S,int X){
// for(;S[X]>=0;X = S[X]);
// return X; 普通遍历
if(S[X]<0)
return X;
else
return S[X] = Find(S,S[X]); //路径压缩使每一个节点都指向它的最终根节点
}
void Input_connection(SetType S){
ElementType u,v; //元素数据类型类型变量
SetName Root1,Root2; //集合的根节点名称
cin>>u>>v;
getchar();
Root1 = Find(S,u-1);
Root2 = Find(S,v-1);
if(Root1 != Root2)
Union(S,Root1,Root2); //若这两个节点没有相连,则连接他们
}
void Check_connection(SetType S){
ElementType u,v;
SetName Root1,Root2;
cin>>u>>v;
getchar();
Root1 = Find(S,u-1);
Root2 = Find(S,v-1);
if(Root1 == Root2) //若两节点根一样,则说明他俩能联通
cout<<"yes\n";
else
cout<<"no\n";
}
void Check_network(SetType S,int n){
int cnt = 0;
for(int i=0;i<n;i++){
if(S[i] < 0) cnt++;
}
if(cnt == 1)
cout<<"The network is connected.\n";
else
cout<<"There are "<<cnt<<" components.\n";
}
int main(){
SetType S;
int n;
char in;
cin>>n;
getchar();
Init(S,n);
do{
cin>>in;
switch(in){
case 'I':Input_connection(S); break; //输入有连线的两台电脑
case 'C':Check_connection(S); break; //检查两台电脑是否相连
case 'S':Check_network(S,n); break; //检查整个系统有几个组件
}
}while(in != 'S');
return 0;
}
题目翻译:
这道题主要考察了对数据结构并查集的理解,以及对并查集的一些基本操作,有以下几个需要注意的点:
1.该题用数组存储一个并查集,没有用到结构体,比较节省空间和便于理解。
2.使用了按秩归并的连接方式,避免了极端情况下二叉树退化成一个链表大大增加时间复杂度。
3.使用了路径压缩的算法优化方式,把每一个节点的父节点设置为根节点,这样的话查找两个节点是否相连只需查看他们的根节点是否相同,减少算法函数执行次数 。
此系列为作者记录数据结构学习文章,由于能力所限,难免有细节处理不当之处,恳请读者谅解并指正。