合根植物

问题描述

  w星球的一个种植园,被分成 m * n 个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。
  这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。


  如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?
输入格式
  第一行,两个整数m,n,用空格分开,表示格子的行数、列数(1<m,n<1000)。
  接下来一行,一个整数k,表示下面还有k行数据(0<k<100000)
  接下来k行,第行两个整数a,b,表示编号为a的小格子和编号为b的小格子合根了。


  格子的编号一行一行,从上到下,从左到右编号。
  比如:5 * 4 的小格子,编号:
  1 2 3 4
  5 6 7 8
  9 10 11 12
  13 14 15 16
  17 18 19 20
样例输入
5 4
16
2 3
1 5
5 9
4 8
7 8
9 10
10 11
11 12
10 14
12 16
14 18
17 18
15 19
19 20
9 13
13 17
样例输出
5
样例说明
  其合根情况参考下图

Algorithm

 这是一个考察并查集的题目,题目很简单,但是如果数据量很大的话,常规的模拟时空复杂度都会超。
因此选择一个好的数据结构很关键。这里参照了[挑战程序设计竞赛(第2版)].巫泽俊.


AC

 1 #include<iostream>
 2 #include<cstring>
 3 
 4 using namespace std;
 5 
 6 const int MAX_N = 1001*1001;
 7 
 8 int par[MAX_N];        // 父亲
 9 int rank[MAX_N];     // 树的高度
10 
11 void Init(int n)
12 {
13     memset(rank, 0, sizeof(rank));
14     for(int i=0;i<n;i++)
15         par[i] = i;
16  } 
17 
18 // 查询树的根 
19 int find(int x)
20 {
21     return (par[x] == x)?x:(par[x] = find(par[x]));
22 }
23 
24 // 合并 x和 y所属的集合 
25 void unite(int x, int y)
26 {
27     x = find(x);
28     y = find(y);
29     if(x == y) return;
30     if(rank[x] == rank[y]){
31         par[x] = y;
32     }
33     else{
34         par[y] = x;
35         if(rank[x] == rank[y]) rank[x]++;
36     }
37 }
38 
39 bool same(int x, int y)
40 {
41     return find(x) == find(y);
42 }
43 
44 int main()
45 {
46     int m, n, k, x, y;
47     while(cin>>m>>n)
48     {    // 居然是从 1 开始的... 
49         int c = m*n+1, s = 0;
50         Init(c);
51         cin>>k;
52         while(k--)
53         {
54             cin>>x>>y;
55             unite(x, y);
56         }
57         // 所以不能有 0 
58         while(--c && c != 0)
59         {
60             if(par[c] == c) s++;
61         }
62         cout<<s<<endl;
63         s = 0;
64     }
65     
66     return 0;
67 }
View Code

 

 2019-02-10

16:32:52

posted @ 2019-02-10 16:34  maybeTang  阅读(327)  评论(0编辑  收藏  举报