题目大意:
输入多个m行n列的矩阵,用0表示输入结束。找出有多少块石油区域,用“@”代表石油,假如两个“@”在横,竖或对角线上相邻,就说它们位于同一区域,对于每个输入,输出一个数表示有几个石油区域。
输入样例:
1 1 * 3 5 *@*@* **@** *@*@* 1 8 @@****@* 5 5 ****@ *@@*@ *@**@ @@@*@ @@**@ 0 0
输出样例:
0 1 2 2
解题思路:
类似于找图中的连通分量个数,把矩阵看成图,八个方向上的点看成邻接点,很容易。
解题步骤:
1、用一个变量cnt保存连通分量的个数,用字符串数组的方式存储输入的矩阵,遍历矩阵中元素,找到元素值为'@'且未访问的元素,按其行号和列号开始深搜;
2、深搜时,邻接点按原点的八个方向,若符合3个条件:不出界、元素值为'@'、未访问,将这个邻接点的行列号递归;
3、在主函数中,每一次把符合点深搜完,连通分量数+1,直到遍历完整个矩阵,此时cnt的值就是连通分量的个数。
代码实现:
#include <iostream>
using namespace std;
#define maxn 100
int m, n;
string s[maxn];
bool vis[maxn][maxn];
void DFS(int u,int v)
{
vis[u][v] = true;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i != 0 || j != 0)
{
int ui = u + i;
int vj = v + j;
if (ui >= 0 && ui < m &&vj >=0 && vj < n && s[ui][vj] == '@' && !vis[ui][vj])
{
DFS(ui, vj);
}
}
}
}
}
int main()
{
while (cin >> m >> n && m)
{
memset(vis, false, sizeof(vis));
int cnt = 0;
for (int i = 0; i < m; i++)
{
cin >> s[i];
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (s[i][j] == '@' && !vis[i][j])
{
DFS(i, j);
cnt++;
}
}
}
cout << cnt << endl;
}
return 0;
}