思路:
此题就是基本的并查集的应用。
关于此题的一些处理技巧:
(1)如何把A->k块表示出来,从而使之容易判断两块地是否可以归并到一起
例如:
把A块划分如上图所示,有4个方向,与其他块有通路的方向标记为1,反之为0,所以A={1 1 0 0},其他同理
(2)如何在map中识别是那一块,然后根据这一块找到它的四个方向的0/1情况呢?这里把A->K等效成了0-11(通过坐标找到map所在位置的字符,然后用此字符减去'A'),然后开辟一个a[11][4]的数组标记A->K每一块的方向
(3)约定把map中的块从左到右,从上到下,标记为第1块,一直到n*m块,通过坐标(i,j),可以计算这是那一块(公式(i-1)*n+j),从而在下面的并查集的函数(初始化函数,find函数,以及归并函数)中容易操作
AC代码:
#include<stdio.h> int father[2505],r[2505]; int map[55][55]; int m,n; int a[11][4]={{1,1,0,0},{1,0,0,1},{0,1,1,0},{0,0,1,1},{1,0,1,0},{0,1,0,1},{1,1,0,1},{1,1,1,0},{0,1,1,1},{1,0,1,1},{1,1,1,1}}; int count; void initial() { int i; for(i=1;i<=m*n;i++) { father[i]=i; r[i]=1; } } int find(int x) { if(father[x]!=x) father[x]=find(father[x]); return father[x]; } void Union(int a,int b) { int x=find(a); int y=find(b); if(x==y)return ; if(r[x]<=r[y]) { father[x]=y; r[y]+=r[x]; count--; } else { father[y]=x; r[x]+=r[y]; count--; } } int main() { int i,j; char x; while(scanf("%d%d",&m,&n)!=-1&&m>=0&&n>=0) { getchar(); for(i=1;i<=m;i++) { for(j=1;j<=n;j++) { scanf("%c",&x); map[i][j]=x-'A'; } getchar(); } count=n*m; initial(); for(i=1;i<=m;i++) for(j=1;j<=n;j++) { if(i-1>0) { if(a[map[i][j]][0]==1&&a[map[i-1][j]][2]==1) Union((i-1)*n+j,(i-2)*n+j); } if(j-1>0) { if(a[map[i][j]][1]==1&&a[map[i][j-1]][3]==1) Union((i-1)*n+j,(i-1)*n+(j-1)); } } printf("%d\n",count); } return 0; }