用的并查集,据说这题还可以用dfs,没去写。
解法:
11个方块,每个方块有四个方向,上下左右,每个方向两个状态,通或者不通。所以很自然想到用二维数组表示。
上 1 下2 左 3 右 4 通1 不通 0
int data[12][5]={{0,0,0,0,0},{0,1,0,1,0},{0,1,0,0,1},{0,0,1,1,0},{0,0,1,0,1},
{0,1,1,0,0},{0,0,0,1,1},{0,1,0,1,1},{0,1,1,1,0},
{0,0,1,1,1},{0,1,1,0,1},{0,1,1,1,1}};
然后并查集呢,题目给你的是个网格,有n*m块,所以就有n*m个节点。我把这n*m个点用1~n*m表示
网格中位置 G[i][j]的地方 表示为 i*m+j+1 就把二维数组中的每一个节点转化为 1~n*m的数字了
然后对于每个点 判断他四周的点的连通性是否匹配 若匹配 就合并
最后遍历找下有几个集合 就是答案
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 5000
int fa[maxn],n,m;
char ch;
int G[55][55];
int data[12][5]={{0,0,0,0,0},{0,1,0,1,0},{0,1,0,0,1},{0,0,1,1,0},{0,0,1,0,1},
{0,1,1,0,0},{0,0,0,1,1},{0,1,0,1,1},{0,1,1,1,0},
{0,0,1,1,1},{0,1,1,0,1},{0,1,1,1,1}};
int init(){
memset(fa,0,sizeof(fa));
for(int i=1;i<=n*m;i++)fa[i]=i;
}
int Find(int x){
return fa[x]==x?x:fa[x]=Find(fa[x]);
}
int Merge(int x,int y){
int p1=Find(x),p2=Find(y);
if(p1!=p2)fa[p2]=p1;
}
int main(){
while(scanf("%d%d",&n,&m)==2){
//i*m+j+1 二维转化一维
getchar();
if(n<=0&&m<=0)break;
init();
memset(G,0,sizeof(G));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%c",&ch);G[i][j]=ch-'A'+1;
}
getchar();
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(i>0){//Up
if(data[G[i][j]][1]&&data[G[i-1][j]][2])Merge(i*m+j+1,(i-1)*m+j+1);
}
if(j>0){//Left
if(data[G[i][j]][3]&&data[G[i][j-1]][4])Merge(i*m+j+1,i*m+j-1+1);
}
if(i<n-1){//Down
if(data[G[i][j]][2]&&data[G[i+1][j]][1])Merge(i*m+j+1,(i+1)*m+j+1);
}
if(j<m-1){//Right
if(data[G[i][j]][4]&&data[G[i][j+1]][3])Merge(i*m+j+1,i*m+j+1+1);
}
}
}
int ans=0;
for(int i=1;i<=n*m;i++){
if(Find(i)==i)ans++;
}
printf("%d\n",ans);
}
return 0;
}