05-树8 File Transfer (25 分)--------C语言

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.

        这题在mooc上陈越老师的课上说过思路,大致来说就是:将一台电脑1和另一台电脑2相连,相当于这两台电脑处于同一个集合内,并且由于这个连线是双向的,也就是说1可以通过这个连线与和2相连的其他电脑连接起来,同理,2也是这样。

        所以换个说法就是,1所在的集合和2所在的集合并在了一起,而要搜索两个电脑是不是连在一起,要跟着连线走,就相当于在寻找根节点的过程,那就是用树来将集合并起来,也就是并查集问题。

        怎么用树将集合并起来呢,那么就是将两个数的根节点连在一起,而这道题中,如果采用一般方法归并的话,会出现运行超时的问题,因为如果一直是要将树中最下面的结点和新的结点(电脑)相连,需要不停地从最下面往上走找到根,第N个元素找N遍,时间复杂度为O(n^2)。

        所以在课上,老师就介绍了按秩归并的方法,分为两种(按树的高度、按元素的个数)。也就是说要么将矮的树并到高的树里,要么将元素个数小的归并到元素个数大的树里。在用数组表示树的时候,我们将结点序号设为数组下标,其中的值便是其父节点的下标,那么根节点的值一般是设为-1(因为没有父节点),而按秩归并中,为了方便的表示,若用树的高度来分,其数组的值为-h(h为树的高度),若用元素个数来分,其值为-n(n为元素个数)。

        对于C语言来说,因为输入输出很快,不像java语言一样,其实可以对运行时间提出更高的要求,而为了得到运行效率更高的代码,老师又介绍了路径压缩的方法。

int Find(int S[], int x)               //路径压缩 
{
    if(S[x]<0) return x;
    else return S[x]=Find(S, S[x]);
}

        上述代码带来的结果是将所有节点都直接连上了根节点,这样直接减少了寻找根节点的时间。运行时间又得到了提高。

        而用路径压缩时,如果采用树的高度来归并,需要函数返回一次,就修改一次树的高度,会非常麻烦,所以一般都是将路径压缩和按元素个数归并结合起来使用。总体代码为:

//05-树8 File Transfer (25 分)
#include<stdio.h>
#define Maxsize 10000
int S[Maxsize];

void Initialize(int N);
void check(void);
void Union(void);
int Find(int S[], int x); 
void judge(int N);

int main()
{
    int N=0, i=0;
    char In;
    scanf("%d", &N);
    Initialize(N);
    do{
        scanf("%c", &In);
        switch(In){
            case 'C': check(); break;
            case 'I': Union(); break;
            case 'S': judge(N); break;
        }
    } while(In!='S');
    
    return 0;
}

void Initialize(int N)    //初始化 
{
    for(int i=0;i<N;i++){
        S[i]=-1;
    }

void check(void)
{
    int c1, c2;
    int root1, root2;
    scanf("%d%d", &c1, &c2);
    root1=Find(S, c1-1);
    root2=Find(S, c2-1);
    if(root1==root2) printf("yes\n");
    else printf("no\n");
}

void Union(void)
{
    int c1, c2;
    int root1, root2;
    scanf("%d%d", &c1, &c2);
    root1=Find(S, c1-1);
    root2=Find(S, c2-1);
    if(S[root1]<S[root2]){
        S[root1]=S[root2]+S[root1];        //按秩归并(元素个数) 
        S[root2]=root1;
    }
    else {
        S[root2]=S[root2]+S[root1];
        S[root1]=root2;
    }
}

int Find(int S[], int x)               //路径压缩 
{
    if(S[x]<0) return x;
    else return S[x]=Find(S, S[x]);
}

void judge(int N)
{
    int cnt=0, i=0;
    for(i=0;i<N;i++){
        if(S[i]<0) cnt++;
    }
    if(cnt==1) printf("The network is connected.");
    else printf("There are %d components.", cnt);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值