注意:在主函数的两个for循环进行深搜前,注意判断是否已访问过,否则产生大量点数为0的色子。另外,因为这个循环每次成功去深搜都是深搜了一个大的连通块,所以色子个数的增加应该在这个循环里,不要放在dfs里~
(之前的思路是,深搜一次,*在深搜时遇到X则点数加1,X深搜时遇到X则点数不加。发现对2行2列的数据*XXX就会出错,因为这样算一个,那个思路算出来的是两个。之后看了网上的思路,参考了一下。两次深搜,学习了~)
这里的深搜都是标记其被访问过,每次深搜都是标记完一个连通块。然后统计了访问的次数,即连通块的个数:色子数、色子的点数。(包括之前油田那题的深搜也是这样。)
inclusive 包含的,exclusive才是排他的~Code:
#include<stdio.h> #include<string.h> #include<stdlib.h> #define MAXN 55 int cmp_int(const void *_a, const void *_b); void dfs(int hs,int ls); void dfsx(int hs,int ls); int w,h; char G[MAXN][MAXN]; int visit[MAXN][MAXN]; int visitx[MAXN][MAXN]; int dir[][4]={{-1,1,0,0},{0,0,1,-1}};//LRDU,前x后y,前水平后竖直 int num[MAXN*MAXN];//相应色子的点数 int cnt;//色子个数 int main() { //freopen("657.in","r",stdin); //freopen("657.out","w",stdout); int thrw=1; while(scanf("%d%d",&w,&h) && w && h) { memset(G,'.',sizeof(G)); memset(visit,0,sizeof(visit)); memset(visitx,0,sizeof(visitx)); for(int i=1;i<=h;++i) { getchar(); for(int j=1;j<=w;++j) { G[i][j]=getchar(); } } cnt=0; memset(num,0,sizeof(num)); for(int i=1;i<=h;++i) for(int j=1;j<=w;++j) if(G[i][j]!='.' && !visit[i][j])//注意这里的!visit条件,不然会打出很多点数为0的色子 { dfs(i,j); cnt++;//色子数增加 //注意这个别放在dfs语句中了,想一想就理解了 //printf("%d %d\n",i,j); } qsort(num,cnt,sizeof(num[0]),cmp_int); printf("Throw %d\n",thrw++); for(int i=0;i<cnt;++i) if(i==0) printf("%d",num[i]); else printf(" %d",num[i]); printf("\n\n"); } return 0; } int cmp_int(const void *_a, const void *_b) { return *(int*)_a-*(int*)_b; } void dfsx(int hs,int ls) {//由X来遍历连通块 if(G[hs][ls]!='X' || visitx[hs][ls]) return ; visitx[hs][ls]=1; for(int i=0;i<4;++i) { int nh=hs+dir[1][i]; int nl=ls+dir[0][i]; dfsx(nh,nl); } } void dfs(int hs,int ls) {//从一点出发,由*和X来遍历连通块 if(G[hs][ls]=='.' || visit[hs][ls]) return ; visit[hs][ls]=1; if(G[hs][ls]=='X' && !visitx[hs][ls]) { dfsx(hs,ls); num[cnt]++;//点数增加 } //else if(G[hs][ls]=='*') //注意这里别加这个判断条件。因为就算是字符X也需要进行下面这个循环的遍历 for(int i=0;i<4;++i) { int nh=hs+dir[1][i]; int nl=ls+dir[0][i]; dfs(nh,nl); } }
原文地址:http://blog.csdn.net/buxizhizhou530/article/details/39034163