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 */
View Code

借助的是UVA 1665 大神的模板

posted @ 2015-09-24 22:33  一麻袋码的玛侬  阅读(443)  评论(0编辑  收藏  举报