UVA 572 油田连通块-并查集解决
题意:8个方向如果能够连成一块就算是一个连通块,求一共有几个连通块。
分析:网上的题解一般都是dfs,但是今天发现并查集也可以解决,为了方便我自己理解大神的模板,便尝试解这道题目,没想到过了。。。
1 #include <cstdio>
2 #include <iostream>
3 #include <sstream>
4 #include <cmath>
5 #include <cstring>
6 #include <cstdlib>
7 #include <string>
8 #include <vector>
9 #include <map>
10 #include <set>
11 #include <queue>
12 #include <stack>
13 #include <algorithm>
14 #define ll long long
15 #define mem(m, a) memset(m, a, sizeof(m))
16 #define repu(i, a, b) for(int i = a; i < b; i++)
17 #define maxn 1100
18 const double PI=-acos(-1.0);
19 using namespace std;
20 struct Node
21 {
22 int val, x, y;
23 bool operator < (const Node a)const
24 {
25 return val > a.val;
26 }
27 Node(int v=0, int x=0, int y=0):val(v), x(x), y(y) {}
28 } nd[maxn*maxn];
29 struct Query
30 {
31 int h, id;
32 bool operator < (const Query a)const
33 {
34 return h>a.h;
35 }
36 Query(int h=0, int id=0):h(h), id(id) {}
37 } q[100010];
38 bool vis[maxn][maxn];
39 int n, m, pre[maxn*maxn];
40 const int dx[]= {0, 0, -1, 1, 1, 1, -1, -1};
41 const int dy[]= {1, -1, 0, 0, 1, -1, 1, -1};
42 int Find(int x)
43 {
44 if(pre[x] == -1) return x;
45 return pre[x] = Find(pre[x]);
46 }
47 bool OK(int x, int y)
48 {
49 return x && y && x<=n && y<=m;
50 }
51 int judge(int x, int y)
52 {
53 int v[5], cnt=0;
54 for(int i=0; i<8; i++)///寻找他周围的四个数字是哪些集合的
55 {
56 int nx=x+dx[i], ny=y+dy[i];
57 if(OK(nx, ny) && vis[nx][ny])///已经遍历过的
58 {
59 int t = Find(m*(nx-1)+ny);
60 v[cnt++] = t;
61 }
62 }
63 sort(v, v+cnt);
64 cnt = unique(v, v+cnt)-v;
65 for(int i=0; i < cnt; i++)
66 pre[v[i]] = m*(x-1)+y;///把筛选下来的全都归入(x,y)中
67 return 1 - cnt;///返回的值也只有-1,0,1
68 }
69 int main()
70 {
71 char c[110][110];
72 int T, t, v;
73 while(~scanf("%d%d", &n, &m) ,n + m)
74 {
75 getchar();
76 int tot=0;
77 repu(i,1,n+1)
78 gets(c[i]);
79 repu(i,1,n+1)
80 {
81 repu(j,0,m)
82 {
83 if(c[i][j] == '*')
84 nd[tot]=Node(1, i, j+1);
85 else
86 nd[tot]=Node(2, i, j+1);
87 tot++;
88 }
89 }
90 ///都是从大到小
91 sort(nd, nd+tot);
92 memset(vis, 0, sizeof vis);
93 memset(pre, -1, sizeof pre);
94 int cnt=0,j = 0;
95 for(; nd[j].val > 1 && j < tot; j++)
96 {
97 ///如果这个点比所查询的点大,则可以加入其坐标
98 cnt += judge(nd[j].x, nd[j].y);
99 vis[nd[j].x][nd[j].y]=1;
100 }
101 printf("%d\n",cnt);
102 }
103 return 0;
104 }
105 /*
106 3 5
107 *@*@*
108 **@**
109 *@*@*
110 */
借助的是UVA 1665 大神的模板
人生就像心电图,想要一帆风顺,除非game-over