思路:
此题就是基本的并查集的应用。
关于此题的一些处理技巧:
(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;
}