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?
Input Specification:
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.
Output Specification:
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.
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.
这道题不需要建一个结构体数组来存父结点和数据,只需要将1-N个数依次表示为0-N - 1,即作为数组下标。数组内容就存其父结点的下标
对于父结点本来应该都是存-1,但是只样写的话若Union就无法得到优化,因为我们需要知道两棵树的大小才可以令小的树和大的树合并
原本的Union
void Union(SetType S,SetName Root1,SetName Root2)
{/*默认Root1和Root2是不同集合的根节点*/
S[Root2] = Root1;
}
这样的话会使得树的高度越来越高Find查找效率也就越低,因此我们的优化方式有两种
- 按秩归并
(1)按高度合并
/*按树高合并*/
void Union(int S[],int Root1,int Root2)
{
if(S[Root1] < S[Root2])/*如果Root1的高度比Root2的高度更高*/
{
S[Root2] = Root1;
}
else
{
if(S[Root1] == S[Root2]) S[Root2]--;/*如果相等则树高加1即--*/
S[Root1] = Root2;
}
}
(2)按规模合并
/*按规模即元素个数合并*/
void Union(int S[],int Root1,int Root2)
{
if(S[Root1] < S[Root2])/*如果Root1的规模比Root2更大*/
{
S[Root1] += S[Root2];/*将Root2的个数加到Root1上*/
S[Root2] = Root1;
}
else
{
S[Root2] += S[Root1];
S[Root1] = Root2;
}
}
完整代码1
#include <iostream>
#include <cstring>
using namespace std;
const int MaxSize = 1e4 + 4;
int S[MaxSize];
int n;
void InitialSetType(int S[], int n);/*初始化集合*/
int Find(int S[],int X);/*查找元素对应根节点*/
void Union(int S[],int Root1,int Root2);/*将两个结点连接到一个集合中*/
void Input_connection(int S[]);/*连接两台计算机*/
void Check_connection(int S[]);/*检查两台计算机是否连通*/
void Count_connection(int S[]);/*输出有几个集合*/
int main()
{
cin >> n;
InitialSetType(S,n);/*初始化集合*/
char c;
do
{
cin >> c;
switch(c)
{
case 'I': Input_connection(S); break;
case 'C': Check_connection(S); break;
case 'S': Count_connection(S); break;
default: break;
}
}while(c != 'S');
return 0;
}
void InitialSetType(int S[],int n)
{
for(int i = 0 ; i < n ; i++)
{
S[i] = -1;/*初始化时每个结点都是单独的结点都是自己的根节点*/
}
}
int Find(int S[],int X)
{
for(; S[X] >= 0/*当根节点小于1时*/; X = S[X]);
return X;
}
/*按树高合并*/
/*void Union(int S[],int Root1,int Root2)
{
if(S[Root1] < S[Root2])/*如果Root1的高度比Root2的高度更高*/
/*{
S[Root2] = Root1;
}
else
{
if(S[Root1] == S[Root2]) S[Root2]--;/*如果相等则树高加1即--*/
/* S[Root1] = Root2;
}
}
/*按规模即元素个数合并*/
void Union(int S[],int Root1,int Root2)
{
if(S[Root1] < S[Root2])/*如果Root1的规模比Root2更大*/
{
S[Root1] += S[Root2];/*将Root2的个数加到Root1上*/
S[Root2] = Root1;
}
else
{
S[Root2] += S[Root1];
S[Root1] = Root2;
}
}
void Input_connection(int S[])
{
int c1,c2;
cin >> c1 >> c2;
int Root1 = Find(S,c1 - 1);
int Root2 = Find(S,c2 - 1);
if(Root1 != Root2)
{
Union(S,Root1,Root2);
}
}
void Check_connection(int S[])
{
int c1,c2,Root1,Root2;
cin >> c1 >> c2;
Root1 = Find(S,c1 - 1);
Root2 = Find(S,c2 - 1);
if(Root1 != Root2)
{
cout << "no" << endl;
}
else
{
cout << "yes" << endl;
}
}
void Count_connection(int S[])
{
int cnt = 0;
for(int i = 0 ; i < n ; i++)
{
if(S[i] < 0)
{
cnt++;
}
}
if(cnt == 1)
{
cout << "The network is connected." << endl;
}
else
{
cout << "There are " << cnt << " components." << endl;
}
}
- 路径压缩
这是针对Find函数
int Find(int S[],int X)
{
if(S[X] <= 0)
{
return X;
}
else
{
return S[X] = Find(S,X);
}
}
这样做方便查找。每找一个元素时都将其根节点赋为其父结点,就实现了路径压缩