- 题目:
- 分析与解答
- 题目:
题目:
多组案例,每组案例输入一个m行n列的字符矩阵,统计字符‘@’组成多少个连通块。如果两个字符‘@’所在的格子相邻(横、竖或对角线),则说明它们属于同一连通块。
Sample Input
1 1*3 5*@*@***@***@*@*1 8@@****@*5 5****@*@@*@*@**@@@@*@@@**@0 0
Sample Output
0122
分析与解答
1.找到油田,然后通过循环遍历他周围的八个位置,不断调用dfs函数,如果连通,则讲连通分量标号
2.循环,找没标记过的油田,然后继续进行1,标号增加
3.油田均已标记完,此时输出标号,就是连通块个数
怎么写bfs:
结束递归的条件有两个,一个是超过了格子的范围,另一个是之前曾经出现过,以及这个格子不是油田。找的话每个油田做标号,是同一联通区域的标上一样的号,最后输出最终的标号即可。调用时机:if(idx[i][j]==0&&pic[i][j]==’@’)这个数没标记过,而且属于油田。bfs里面用两个for循环直接把他八个方向都扫描了一遍,并且如果满足条件就进行初始化,此时如果在同一个连通区域他们的值是相同的,所以main里调用bfs时一定是发现了不同的连通区域,如果要求不同连通区域个数,就只用在main里面更改cnt的个数
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100+5;
char pic[maxn][maxn];
int m,n,idx[maxn][maxn];void DFS(int r,int c,int id)
{if(r<0||r>=m||c<0||c>=n) return ;if(idx[r][c]>0||pic[r][c]!='@') return ;idx[r][c]=id;for(int dr=-1;dr<=1;dr++)for(int dc=-1;dc<=1;dc++)if(dr!=0||dc!=0)DFS(r+dr,c+dc,id);
}
int main()
{while(scanf("%d%d",&m,&n)!=EOF&&m&&n){for(int i=0;i<m;i++) scanf("%s",pic[i]);memset(idx,0,sizeof(idx));int cnt=0;for(int i=0;i<m;i++)for(int j=0;j<n;j++)if(idx[i][j]==0&&pic[i][j]=='@')DFS(i,j,++cnt);printf("%d\n",cnt);}return 0;
}
也可以写八条DFS调用
#include<cstdio>
#include <cstring>
using namespace std;
#define maxn 105
char a[maxn][maxn];
bool vis[maxn][maxn];
int n,m;
void DFS(int x,int y)
{if(x<0||x>=n||y<0||y>=m) return ;if(a[x][y]=='*'||vis[x][y]) return;vis[x][y]=true;DFS(x+1,y+1);DFS(x+1,y);DFS(x+1,y-1);DFS(x,y-1);DFS(x-1,y-1);DFS(x-1,y);DFS(x-1,y+1);DFS(x,y+1);
}
int main()
{while(scanf("%d%d",&n,&m)!=EOF){if(n+m==0) break;for(int i=0; i<n; i++)scanf("%s",a[i]);int sum=0;memset(vis,false,sizeof(vis));for(int i=0; i<n; i++)for(int j=0; j<m; j++)if(!vis[i][j]&&a[i][j]=='@'){DFS(i,j);sum++;}printf("%d\n",sum);}return 0;
}