PAT甲级1013题解——并查集+路径压缩

题目分析:

本题初步浏览题目就知道是并查集的模板题,数据输入范围N为1~1000,则M的范围为0~1000^2,通过结构体记录每一对连线的关系,p[]数组记录每个节点的跟,对于k次查询,每次都要重新维护p[]数组,而每次的区别在于都要排除被占领的节点重新维护p[]数组的节点的链接关系,而最终的答案就是集合数-2(占领点一定是单独的集合,n个集合需要n-1条边就能相连)

 1 #include<iostream>
 2 using namespace std;
 3 
 4 struct Node{
 5     int from;
 6     int to;
 7 }a[1000005];
 8 int p[1005];
 9 int n, m, k;
10 
11 int find(int x){
12     int y = x;
13     while(p[x] != x){
14         x = p[x];
15     }
16     //路径压缩 此时x是根 
17     while(p[y] != x){
18         int t = y;            //对于路径上的每个y节点都要保留一下 
19         y = p[y];            //此时我们还是按照上述的顺序去查询根 
20         p[t] = x;            //y已经变的p[y]的值,而t则记录了之前y的值 而p[之前的y]已经用不到了,我们将其路径压缩,把它的跟直接变为x 
21     }
22     return x;
23 }
24 
25 void Union(int x, int y){
26     int fx = find(x);
27     int fy = find(y);
28     if(fx != fy){
29         p[fx] = fy;
30     }    
31 }
32 
33 void init(int occupy){
34     for(int i = 1; i <= n; i++) p[i] = i;
35     for(int i = 1; i <= m; i++){
36         //根据a中的一对一对的关系维护并查集 同时注意被占领的城市不参与其中
37         if(a[i].from != occupy && a[i].to != occupy){
38             Union(a[i].from, a[i].to);
39         }
40     }
41 }
42 
43 void run(){
44     int ans = 0;
45     for(int i = 1; i <= n; i++){
46         if(p[i] == i){
47             ans++;
48         }
49     }    
50     printf("%d\n", ans - 2);
51 } 
52 
53 int main(){
54     while(scanf("%d%d%d", &n, &m, &k) != EOF){
55         for(int i = 1; i <= m; i++){
56             scanf("%d%d", &a[i].from, &a[i].to);            
57         }
58         int occupy; 
59         for(int i = 1; i <= k; i++){
60             scanf("%d", &occupy);
61             //每次都要初始化并查集 
62             init(occupy);
63             //获取每次至少要添加的线条数 
64             run();
65         }
66     }
67     return 0;
68 }

 

posted on 2019-10-13 15:28  白泽talk  阅读(327)  评论(0编辑  收藏  举报