/* 问题:在n*m的图中,确定有几个@块,块符合以下条件:其中任意对@块均直接或间接相通,两个@直接相邻或者对角相邻即被视为连通 输入:m(行号) n(列号),m=0标志输入结束,1<=m,n<=100,接下来是m行每行中有n个字符。每个字符对应一块土地,*代表没有石油,@代表有石油 输出:对于每个格子,输出有多少个石油存储区。2个不同的石油处垂直,水平,对角线属于同一个石油存储区。石油存储区<=100 思路:对图上所有位置设置标记位,该标记仅对@有效,按从左到右,从上到下顺序遍历地图上所有位置,如果遍历到@,且未被标记,则所有与其直接相邻或间接相邻的@点与其一起 组成一个块,将该块中所有的@位置标记为已经计算。 关键: 1 按行输入,maze[i] + 1,scanf("%s",maze[i]+1);//不能加上\n,且maze[i]后面需要加上1 2 凡是用栈均是深度优先 3 薄弱:二维指针 4 在设置剪枝标记时与递归过程分开,在递归的主调函数中要进行过滤,每递归结束1次,进行一次累加 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 101 bool mark[N][N];//剪枝标记 char maze[N][N];//迷宫坐标,存储元素 int goNext[][2] = {-1,1, 0,1, 1,1, -1,0, 1,0, -1,-1, 0,-1, 1,-1 };//8个位置的下一个走法 //n:行号,m:列号,x:横坐标,y:纵坐标 void DFS(int x,int y,int n,int m) { //判定8个位置的下一个走法 int iXNext,iYNext; for(int i = 0; i < 8 ; i++) { iXNext = x + goNext[i][0]; iYNext = y + goNext[i][1]; //如果已经标记或者超出范围或者为*均跳过 if(true==mark[iXNext][iYNext] || '*'==maze[iXNext][iYNext] || (iXNext < 0 || iXNext > n || iYNext < 0 || iYNext >m)) { continue; } else { //如果没有则递归调用,调用之前先设置标记为真 mark[iXNext][iYNext] = true; DFS(iXNext,iYNext,n,m); } } } int main(int argc,char* argv[]) { int n,m; int i,j; while(EOF!=scanf("%d %d",&n,&m)) { if(n < 1 || n > 100 || m < 1 || m > 100) { break; } //接受输入信息 for(i = 1 ; i <=n ; i++) { //按行输入? scanf("%s",maze[i]+1);//不能加上\n } //初始化剪枝标记 for(i = 1 ; i <= n ; i++) { for(j = 1 ; j <= m ; j++) { mark[i][j] = false; } } //开始进行递归遍历,设置限定条件 int iCnt = 0;//设定石油存储区计数器初始化为0 for(i = 1 ; i <= n ; i++) { for(j = 1; j <= m ; j++) { if(true==mark[i][j] || '*'==maze[i][j]) { continue; } else { DFS(i,j,n,m); iCnt++; } } } printf("%d\n",iCnt); } system("pause"); getchar(); return 0; }