原题是英文的:题目详情 - 05-树8 File Transfer (pintia.cn)
我用软件翻译了一下:
我们有一个计算机网络和一系列双向连接。这些连接中的每一个都允许文件从一台计算机传输到另一台计算机。有没有可能从网络上的任何一台计算机向其他计算机发送文件?
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”。在每个案例的末尾,如果有任何一对计算机之间的路径,打印一行“网络已连接”;或者“有k个组件”,其中k是这个网络中连接组件的数量
按照课件说的我将代码写完
#include <iostream>
using namespace std;
int map[10010];
//通过根的连接,将两个集合合并
void link(int a,int b){
map[b] = a;
}
//找到a的根
int find(int a){
for( ; map[a]>0 ; a=map[a]);
return a;
}
//将两个节点合并为同一个集合中
void connection(int a,int b){
int aroot,broot;
aroot = find(a);
broot = find(b);
if(aroot != broot){
link(aroot,broot);
}
}
//两个节点是否连接
void is_connection(int a,int b){
int aroot,broot;
aroot = find(a);
broot = find(b);
if(aroot != broot){
cout<<"no"<<endl;
return;
}
cout<<"yes"<<endl;
return;
}
//判断这些电脑有多少个区域
void check_components(int n){
int check_int = 0;
for(int i=1;i<=n;i++){
if(map[i] == -1) check_int++;
}
if(check_int>1){
printf("There are %d components.",check_int);
return;
}
printf("The network is connected.");
return;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) map[i] = -1;
char ch;
int a,b;
while(1){
cin>>ch;
if(ch=='S') break;
scanf("%d %d\n",&a,&b);
if(ch=='C'){
is_connection(a,b);
}
if(ch=='I'){
connection(a,b);
}
}
check_components(n);
return 0;
}
提交上去结果超时了
又看了一遍课件,突然发现自己连接根节点的函数只考虑了我们需要通过连接两个节点的根节点来减少这个树的高度,但是忽略了一件事情,就是高树接到低树上还是会增加树的高度,但是如果是低树接到高树的话,并不会增加树的高度,树的高度小了,我们find函数所进行的循环次数也就变少了,那么我们时间也就变少了。所以我将link函数稍微修改了一下,如果是同高的话,那么哪棵树连哪棵树都可以。如下:
void link(int a,int b){
if(map[a] < map[b]){
map[b] = a;
}else{
if(map[a] == map[b]) map[b]--;
map[a] = b;
}
return;
}
画个图更加容易理解:
改完代码整体如下:
#include <iostream>
using namespace std;
int map[10010];
//通过根的连接,将两个集合合并
void link(int a,int b){
if(map[a] < map[b]){
map[b] = a;
}else{
if(map[a] == map[b]) map[b]--;
map[a] = b;
}
return;
}
//找到a的根
int find(int a){
for( ; map[a]>0 ; a=map[a]);
return a;
}
//将两个节点合并为同一个集合中
void connection(int a,int b){
int aroot,broot;
aroot = find(a);
broot = find(b);
if(aroot != broot){
link(aroot,broot);
}
}
//两个节点是否连接
void is_connection(int a,int b){
int aroot,broot;
aroot = find(a);
broot = find(b);
if(aroot != broot){
cout<<"no"<<endl;
return;
}
cout<<"yes"<<endl;
return;
}
//判断这些电脑有多少个区域
void check_components(int n){
int check_int = 0;
for(int i=1;i<=n;i++){
if(map[i] < 0) check_int++;
}
if(check_int>1){
printf("There are %d components.",check_int);
return;
}
printf("The network is connected.");
return;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) map[i] = -1;
char ch;
int a,b;
while(1){
cin>>ch;
if(ch=='S') break;
scanf("%d %d\n",&a,&b);
if(ch=='C'){
is_connection(a,b);
}
if(ch=='I'){
connection(a,b);
}
}
check_components(n);
return 0;
}