题目描述:
我们有一个计算机网络和一个双向连接列表。每一个连接都允许文件从一台计算机传输到另一台计算机。有可能从网络上的任何一台计算机向其他计算机发送文件吗?
Input Specification:
每个输入文件包含一个测试用例。对于每个测试用例,第一行包含N(2≤N≤10^4),即网络中计算机的总数。然后,网络中的每台计算机由1到n之间的一个正整数表示,然后在以下几行中,输入的格式如下:
I c1 c2
其中I表示输入c1和c2之间的连接;或
C c1 c2
其中C表示检查是否可以在c1和c2之间传输文件;或
S
S代表停止这个用例
Output Specification:
对于C用例可能或不可能在c1和c2之间分别传输文件,请在一行中打印“yes”或“no”。在每个案例的末尾,打印一行“The network is connected”。或者“There are k components”,其中k是这个网络中连接的组件的数量。
Sample Input 1:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S
Sample Output 1:
no
no
yes
There are 2 components.
Sample Input 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
Sample Output 2:
no
no
yes
yes
The network is connected.
思路
使用并查集的方法来解。如果两个元素的根节点一样即为连通,否则不连通。
代码
#include<bits/stdc++.h>
using namespace std;
#define MAX 10002
int father[MAX]; //存放父节点
bool isRoot[MAX];
//查找x所在集合的根节点
int findFather(int x){
int a=x;
while(x!=father[x]){
x=father[x];
}
//路径压缩,使路径上所有结点都指向根节点
while(a!=father[a]){
int z=a;
a=father[a];
father[z]=x;
}
return x;
}
//合并集合
void Union(int a,int b){
int faA=findFather(a);
int faB=findFather(b);
if(faA!=faB){
father[faA]=faB;
}
}
int main(){
int N;
cin>>N;
char ch;
int n1,n2;
cin>>ch;
for(int i=1;i<=N;i++){//设置每个元素父节点为自己
father[i]=i;
isRoot[i]=false;
}
while(ch!='S'){
cin>>n1>>n2;
if(ch=='C'){
if(findFather(n1)==findFather(n2)){
cout<<"yes"<<endl;
}
else{
cout<<"no"<<endl;
}
}
if(ch=='I'){
Union(n1,n2);
}
cin>>ch;
}
for(int i=1;i<=N;i++){
isRoot[findFather(i)]=true;//集合的父节点为根
}
int ans=0;//记录集合的数目
for(int i=1;i<=N;i++){
ans+=isRoot[i];
}
if(ans==1){
cout<<"The network is connected.";
}
else{
cout<<"There are "<<ans<<" components.";
}
return 0;
}