第五周之05-树8 File Transfer

题目详情:

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.

简单翻译:

先给一个正整数N,表示的电脑编号从1~N,然后给出三种操作:检查两台电脑有没有连接,连接两台电脑,结束,最后还要看这1~ N台电脑连成了几个局域网,如果全部连接就打印全部连接,否则就打印有几个局域网

主要思路:

考察并查集,用类似树的思想构建,不过Set[i]表示序号为i的节点的根节点,而根节点的绝对值则表示这个集合里有多少节点,每个集合只有一个根节点,

并的操作是将小集合往大集合里面并,小集合根节点的值修改为大集合的根节点下标,大集合根节点加上小集合根节点里的值

查的操作利用了路径压缩,如果当前节点是根节点,直接返回,否则就以当前节点递归查找并返回查找到的值

第一次写错误:

题目中集合下标是从1开始,初始化集合要从1开始

代码实现:

/*
集合初始化
检查两台电脑有没有连接就是看他们集合根节点相不相同
连接两台电脑就是将它们各自归属的集合合并,小的往大的里面合并
看这1~N台电脑连成了几个局域网就是找有几个根节点
利用路径压缩,查找时将集合树变矮
*/
#include 
#include 
#define MAX_SIZE 100005
#define CHECK 'C'
#define INPUT 'I'
#define STOP 'S'
int Set[MAX_SIZE];  //Set[i]的含义是下标为i的节点的父节点
int FindRoot(int data) {   //查找data所在集合根节点
    if(Set[data] < 0) {   //Set[data]的值是-1说明data就是根节点
        return data;
    }
    else {
        return Set[data] = FindRoot(Set[data]);  //路径压缩,直接连接到根节点并返回根节点
    }
}
void Connect(int a, int b) {    //connect函数实际上是集合的并预算
    int roota = FindRoot(a);
    int rootb = FindRoot(b);
    if(abs(Set[roota]) >= abs(Set[rootb])) {    //为了避免树太高,将小集合往大集合里面并
        Set[roota] += Set[rootb];   //根节点里保存的绝对值是这个集合里节点的数量
        Set[rootb] = roota;
    }
    else {
        Set[rootb] += Set[roota];
        Set[roota] = rootb;
    }
    return;
}
int Exam(int a, int b) {
    int roota = FindRoot(a);
    int rootb = FindRoot(b);
    if(roota == rootb) {
        return 1;
    }
    else {
        return 0;
    }
}
void Count(int nodeNum) {
    int num = 0;
    for(int i = 1; i <= nodeNum; i++) {
        if(Set[i] < 0) {
            num++;
        }
    }
    if(num == 1) {
        printf("The network is connected.");
    }
    else {
        printf("There are %d components.", num);
    }
    return;
}
int main() {
    int N;
    scanf("%d", &N);
    getchar();
    for(int i = 1; i <= N; i++) {
        Set[i] = -1;
    }
    char operation;
    while(scanf("%c", &operation) && operation != STOP) {
        int a, b;
        scanf("%d %d", &a, &b);
        getchar();
        int flag = 0;
        switch (operation) {
            case INPUT:
                Connect(a, b);
                break;
            case CHECK: {
                flag = Exam(a, b);
                if(flag) {
                    printf("yes\n");
                }    
                else {
                    printf("no\n");
                }
                break;
            }
        }
    }
    Count(N);
    return 0;
}

你可能感兴趣的:(数据结构,数据结构,算法)