2 2 DK HF 3 3 ADC FJK IHE -1 -1
2 3
解题思路:按行对每个节点map(i,j),找到其下方及右方的水管类型,判断其是否能与map(i,j)相连。在这题中只需要判断两个方向而不是四方方向。如下
1 2 3
4 5 6
从1判断2节点是否与1能够相连;若相连则把1和2放入到同一个集合类中,当下次从2搜索时,由于1和2已经在一个集合类中,所以不需要对1进行搜索;如果1和2无法连在一起,那么从2搜到1也是无法相连的。所以只需要搜索节点下方和右方的区域。
从上面给出的类型可以看出,遇到A,B,F,G这四种类型的水管时,不用搜索其下方的区域,因为无论其下方是什么类型都不可能与这四种水管相连。同样若是A,C,E,H这样的类型时也不需要考虑其右边的情况。
当前区域要想与下方的区域连在一起,则下方的水管类型只能下面的类型A,B,E,G,H,J,K。则样若与右方区域相连,右方区域的类型为A,C,F,G,H,I,K
#include<stdio.h> #include<string.h> // char str[2][9]={{"ABEGHJK"},{"ACFGHIK"}}; int f[2505],m,n; char map[52][52]; int check(int x,int y) { if(x>=0 && x<m && y>=0 && y<n)return 1; return 0; } int getFather(int a) { while(a!=f[a])a=f[a]; return a; } /** 合并两个集合 */ void Union(int a,int b) { int root1=getFather(a); int root2=getFather(b); if(root1!=root2) { if(root1<root2)f[root2]=root1; else f[root1]=root2; } } /** * 判断两个型号的水管是否可以连在一起 */ int judge(char c,int flag) { int i; for(i=0;i<7;i++) { if(str[flag][i]==c)return i+1; } return 0; } void process() { int i,j,dx,dy; char c; for(i=0;i<=n*m;i++)f[i]=i; for(i=0;i<m;i++) { for(j=0;j<n;j++) { c=map[i][j]; //判断下方,当前区域的类型是除A,B,F,G以外的。 if(c=='C' || c=='D' || c=='E' || c=='H' || c=='I' || c=='J' || c=='K') { dx = i+1; dy = j; if(check(dx,dy)) { //下方区域是否是 A,B,E,G,H,J,K之一 if(judge(map[dx][dy],0)) { //合并两个区域 Union(i*n+j,dx*n+dy); } } } //判断右方 if(c=='B' || c=='D' || c=='F' || c=='G' || c=='I' || c=='J' || c=='K') { dx=i; dy=j+1; if(check(dx,dy)) { //右方区域是否是A,C,F,G,H,I,K之一 if(judge(map[dx][dy],1)) { Union(i*n+j,dx*n+dy); } } } } } int result=0; for(i=0;i<n*m;i++)if(f[i]==i)result++; printf("%d\n",result); } int main() { int i; while(scanf("%d%d",&m,&n)) { if(m<0 || n<0)break; for(i=0;i<m;i++)scanf("%s",map[i]); process(); } return 0; }