hrbustoj 1073:病毒(并查集,入门题)
病毒
Time Limit: 1000 MS Memory Limit: 65536 K
Total Submit: 719(185 users) Total Accepted: 247(163 users) Rating: Special Judge: No
Description
某种病毒袭击了某地区,该地区有N(1≤N≤50000)人,分别编号为0,1,...,N-1,现在0号已被确诊,所有0的直接朋友和间接朋友都要被隔离。例如:0与1是直接朋友,1与2是直接朋友,则0、2就是间接朋友,那么0、1、2都须被隔离。现在,已查明有M(1≤M≤10000)个直接朋友关系。如:0,2就表示0,2是直接朋友关系。
请你编程计算,有多少人要被隔离。
Input
第一行包含两个正整数N(1≤N≤50000),M(1≤M≤100000),分别表示人数和接触关系数量;
在接下来的M行中,每行表示一次接触,;
每行包括两个整数U, V(0 <= U, V < N)表示一个直接朋友关系。
Output
输出数据仅包含一个整数,为共需隔离的人数(包含0号在内)。
Sample Input
100 4
0 1
1 2
3 4
4 5
Sample Output
3
并查集,入门题。
思路是先根据关系建立关系树,然后记录0号小朋友的根节点,依次与剩下所有的小朋友的根节点比较,相等则计数+1,表示这是和0号小朋友有关系的,即被感染的人。最后输出总计数(即被0号小朋友感染的人数)。
套模板很容易过。
代码:
1 #include <stdio.h>
2
3 /* 并查集模板
4 */
5 int UFS_NUM; //并查集中元素总数
6 typedef struct node{
7 int data; //节点对应的编号
8 int rank; //节点对应秩
9 int parent; //节点对应的双亲下标
10 }UFSTree; //并查集树的节点类型
11 void MAKE_SET(UFSTree t[]) //初始化并查集树
12 {
13 int i;
14 for(i=0;i<UFS_NUM;i++){
15 t[i].data = i; //数据为该点编号
16 t[i].rank = 0; //秩初始化为0
17 t[i].parent = i; //双亲初始化为指向自己
18 }
19 }
20 int FIND_SET(UFSTree t[],int x) //在x所在的子树中查找集合编号
21 {
22 if(t[x].parent == x) //双亲是自己
23 return x; //双亲是自己,返回 x
24 else //双亲不是自己
25 return FIND_SET(t,t[x].parent); //递归在双亲中查找x
26 }
27 void UNION(UFSTree t[],int x,int y) //将x和y所在的子树合并
28 {
29 x = FIND_SET(t,x); //查找 x 所在分离集合树的编号
30 y = FIND_SET(t,y); //查找 y 所在分离集合树的编号
31 if(t[x].rank > t[y].rank) //y 节点的秩小于 x节点的秩
32 t[y].parent = x; //将 y 连接到 x 节点上,x 作为 y 的双亲节点
33 else{ //y 节点的秩大于等于 x 节点的秩
34 t[x].parent = y; //将 x 连接到 y 节点上,y 作为 x 的双亲节点
35 if(t[x].rank==t[y].rank) //x 和 y的双亲节点秩相同
36 t[y].rank++; //y 节点的秩增 1
37 }
38 }
39 int main()
40 {
41 int i,n,m,x,y;
42 while(scanf("%d%d",&n,&m)!=EOF){
43 UFSTree t[50005];
44 UFS_NUM = n;
45 MAKE_SET(t);
46 for(i=1;i<=m;i++){
47 scanf("%d%d",&x,&y);
48 UNION(t,x,y);
49 }
50 int f0 = FIND_SET(t,0);
51 int sum=0;
52 for(i=0;i<n;i++)
53 if(FIND_SET(t,i)==f0)
54 sum++;
55 printf("%d\n",sum);
56 }
57 return 0;
58 }
Freecode : www.cnblogs.com/yym2013