PTA习题:05-树8 File Transfer (25分)和基础实验4-2.8 部落 (25分)

05-树8 File Transfer (25分)和基础实验4-2.8 部落 (25分)

考察并查集

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≤10​^4​​), 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
最后数数有多少个结点的父结点是负数,就有多少个连通域。

C语言代码:

#include<stdio.h>
#include<stdlib.h>
struct Node
{
 int data;
 int parent;
};
typedef struct Node * group;
int Findroot(int n);
void Connect(int C1, int C2);
group c;//数组c存储集合元素
int main()
{
 int n;
 scanf("%d\n", &n);
 c = (group)malloc(n * sizeof(struct Node));
 //将所有结点均设为单独的一个域
 int i;
 for (i = 0; i < n; i++)
 {
  c[i].data = i + 1;
  c[i].parent = -1;
 }
 char operate;
 int C1, C2;
 int root1, root2;
 scanf("%c", &operate);
 while (operate != 'S')
 {
  scanf("%d", &C1);
  scanf("%d\n", &C2);
  switch (operate)
  {
  case 'C':
   root1 = Findroot(C1);
   root2 = Findroot(C2);
   if (root1 == root2)
   {
    printf("yes\n");
   }
   else
   {
    printf("no\n");
   }
   break;
  case 'I':
   Connect(C1, C2);
   break;
  }
  scanf("%c", &operate);
 }
 int count = 0;
 for (i = 0; i < n; i++)
 {
  if (c[i].parent < 0) { count++; }
 }
 if (count == 1) { printf("The network is connected."); }
 else { printf("There are %d components.", count); }
 return 0;
}
//带路径压缩的查找根结点
int Findroot(int n)
{
 if (c[n - 1].parent < 0) { return n - 1; }
 else
 {
  return c[n - 1].parent = Findroot(c[c[n - 1].parent].data);
 }
}
//集合的合并
void Connect(int C1, int C2)
{
 int root1, root2;
 root1 = Findroot(C1);
 root2 = Findroot(C2);
 if (root1 != root2)
 {
  //要按秩归并,否则树高容易长高
  if (c[root1].parent <= c[root2].parent)
  {
   c[root1].parent = c[root1].parent + c[root2].parent;
   c[root2].parent = root1;
  }
  else
  {
   c[root2].parent = c[root1].parent + c[root2].parent;
   c[root1].parent = root2;
  }
 }
 }

另一道题也是考察并查集,方法基本一致,也一起写进来了。

在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。

输入格式:
输入在第一行给出一个正整数N(≤10​^4​​),是已知小圈子的个数。随后N行,每行按下列格式给出一个小圈子里的人:
K P[1] P[2] ⋯ P[K]
其中K是小圈子里的人数,P[i](i=1,⋯,K)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过10^​4​​。
之后一行给出一个非负整数Q(≤10​^4​​),是查询次数。随后Q行,每行给出一对被查询的人的编号。

输出格式:
首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出Y,否则输出N。

输入样例:

4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7

输出样例:

10 2
Y
N

C语言实现:

#include<stdio.h>
#include<stdlib.h>
int * s;
int max = 1;//max记录最大序号,也即社区总人数
void Connect(int index1, int index2);
int Findroot(int index);
int main()
{
 int N, K, index1, index2;
 scanf("%d", &N);
 s = (int *)malloc(10001 * sizeof(int));
 int i, j;
 //初始化
 for (i = 0; i <= 10000; i++)
 {
  s[i] = -1;
 }
 for (i = 0; i < N; i++)
 {
  scanf("%d", &K);
  scanf("%d", &index1);
  if (index1 > max) { max = index1; }
  for (j = 1; j < K; j++)
  {
   scanf("%d", &index2);
   if (index2 > max) { max = index2; }
   Connect(index1, index2);
  }
 }
 int count = 0;//count记录部落个数
 for (i = 1; i <= max; i++)
 {
  if (s[i] < 0) { count++; }
 }
 printf("%d %d\n", max, count);
 //判断是否属于同一集合
 int Q;
 scanf("%d", &Q);
 int d1, d2;
 for (i = 0; i < Q; i++)
 {
  scanf("%d %d", &d1, &d2);
  d1 = Findroot(d1);
  d2 = Findroot(d2);
  if (d1 == d2) { printf("Y\n"); }
  else { printf("N\n"); }
 }
 return 0;
}
//集合按秩归并
void Connect(int index1, int index2)
{
 int root1, root2;
 root1 = Findroot(index1);
 root2 = Findroot(index2);
 if (s[root1] < s[root2])
 {
  s[root1] = s[root1] + s[root2];
  s[root2] = root1;
 }
 else
 {
  s[root2] = s[root1] + s[root2];
  s[root1] = root2;
 }
}
//带路径压缩的查找根结点
int Findroot(int index)
{
 if (s[index] < 0) { return index; }
 else
 {
  return s[index] = Findroot(s[index]);
 }
}
发布了21 篇原创文章 · 获赞 2 · 访问量 1628

猜你喜欢

转载自blog.csdn.net/wulila/article/details/105453703