首页 > 代码库 > UVa 657 掷色子
UVa 657 掷色子
题意:就是有一张大图,每个像素即格子只可能是 . * X 三种,分别代表背景、色子、色子的点数。两个格子是相邻的或连通的,当且仅当两个格子是*或X,且有公共边,即上下左右四个方向,对角不算,即四连块。将一个连通块看做一个色子,将这个连通块中的X的连通块个数看做该色子的点数。
思路:两次深搜。第一次是由*和X来深搜每个连通块,在深搜每个连通块时由X来深搜X的连通块个数。这里可以通过两个标记数组visit来表示是否访问过,visitx来表示是否访问深搜X过。(也可以将X改为*、*改为.的方式实现,不用标记数组。之前我想的是用一个标记数组,然后对其值的判断来实现,不如两个标记数组来得简便和直观)
思路:两次深搜。第一次是由*和X来深搜每个连通块,在深搜每个连通块时由X来深搜X的连通块个数。这里可以通过两个标记数组visit来表示是否访问过,visitx来表示是否访问深搜X过。(也可以将X改为*、*改为.的方式实现,不用标记数组。之前我想的是用一个标记数组,然后对其值的判断来实现,不如两个标记数组来得简便和直观)
注意:在主函数的两个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); } }
UVa 657 掷色子
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。