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 containsNNN (2≤N≤1042\le N\le 10^42≤N≤104), the total number of computers in a network. Each computer in the network is then represented by a positive integer between 1 andNNN. Then in the following lines, the input is given in the format:
I c1 c2
where I
stands for inputting a connection between c1
andc2
; or
C c1 c2
where C
stands for checking if it is possible to transfer files betweenc1
andc2
; 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 betweenc1
andc2
, 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 arek
components." wherek
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. 这道题考察的是集合的并查运算,同时运用了按秩归并和路径压缩的优化方法。。。同时也让我看到了JAVA和C++的效率。同样的逻辑,java几乎全部超时,而C++一次通过 这道题的思路是,以数组结构来组织集合(模拟树结构),其中数组的下标值集合元素的值,数组的值是该位置的父节的值(也就是父节点的下标),其中根结点在数组中 的值为负数(-树的高度),
程序初始化的时候,将数组中每个位置的值都设为-1,即再没有连接前,每个节点都是一个独立的集合。
C++AC代码:
#include <iostream> #include <stdio.h> using namespace std; int s[10005]; int N; void input_connect(); void check_connect(); void stop_connect(); int finds(int k); void unions(int root1,int root2); int main() { scanf("%d",&N); for(int i=0; i<N; i++) { s[i] = -1; } char cp; do { scanf("%s",&cp); switch(cp) { case 'I': input_connect(); break; case 'C': check_connect(); break; case 'S': stop_connect(); break; } } while(cp!='S'); return 0; } void input_connect() { int a,b; scanf("%d%d",&a,&b); int root1 = finds(a-1); int root2 = finds(b-1); if(root1!=root2) { unions(root1,root2); } } void check_connect() { int a,b; scanf("%d%d",&a,&b); int root1 = finds(a-1); int root2 = finds(b-1); if(root1==root2) { printf("yes\n"); } else { printf("no\n"); } } void stop_connect() { int cnt = 0; for(int i=0; i<N; i++) { if(s[i]<0) { cnt++; } } if(cnt==1) { printf("The network is connected.\n"); } else { printf("There are %d components.\n",cnt); } } //用到了路径压缩 int finds(int k) { if(s[k]<0) { return k; } return s[k] = finds(s[k]); } //用到了按秩归并 void unions(int root1,int root2) { if(s[root1]<s[root2]) { s[root2] = root1; } else if(s[root1]>s[root2]) { s[root1] = root2; } else { s[root1] = root2; s[root2]--; } }
java超时代码:~~~~~import java.util.Scanner; import java.util.Arrays; public class Main{ private static int[] s; private static Scanner scan = new Scanner(System.in); public static void main(String[] args) { int N = scan.nextInt(); s = new int[N]; Arrays.fill(s,-1); char cp; do{ cp = scan.next().charAt(0); switch(cp){ case 'I':input_connect();break; case 'C':check_connect();break; case 'S':stop_connect(N);break; } }while(cp!='S'); } public static void input_connect(){ int a = scan.nextInt(); int b = scan.nextInt(); int root1 = find(a-1); int root2 = find(b-1); if(root1!=root2){ union(root1,root2); } } public static void check_connect(){ int a = scan.nextInt(); int b = scan.nextInt(); int root1 = find(a-1); int root2 = find(b-1); if(root1==root2){ System.out.println("yes"); }else{ System.out.println("no"); } } public static void stop_connect(int N){ int cnt = 0; for(int i=0;i<N;i++){ if(s[i]<0){ cnt++; } } if(cnt==1){ System.out.println("The network is connected."); }else{ System.out.println("There are "+cnt+" components."); } } //用到了路径压缩 public static int find(int k){ if(s[k]<0){ return k; } return s[k] = find(s[k]); } //用到了按秩归并 public static void union(int root1,int root2){ if(s[root1]<s[root2]){ s[root2] = root1; }else if(s[root1]>s[root2]){ s[root1] = root2; }else{ s[root1] = root2; s[root2]--; } } }