BFS广度优先搜索指的是在子集树中优先遍历同一层的所有节点,然后再深入遍历更深一层的节点,在地图类的问题中一般以某一层地图为初始节点同时扩展来遍历全图。
问题描述:编程计算由*围成的下列图形的面积。面积的计算方法是统计*所围成的闭合曲线中的点的数目,如下图所示在10*10的二维数组中,有*围住了15个点,因此面积为15。(题目中以1代替*)
算法思想:这是一个标准的BFS地图题,但是需要经过一步转化,无疑就是将图中的*围出来的0数出来,但是计算0的数量的时候,我们要先把不符合要求的0全部转化为1,如下图的阴影部分:
转化的方法就是构造一个包含每一个点结构体的队列(能用队列的时候尽量不要用二维数组),从最外层的所有点一一进行广度拓展,满足不越界且值不为1的点全部置1,这样围成的0的点不会被改变而问题所求的面积就很显而易见了。另外提醒一点,地图题上的广搜问题十有八九会用到方向变量。源代码如下:
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
int m,n,sum; //m行,n列,sum为总的数字数目
int a[100][100]; //a[x][y]表示x行,y列的值
int ans;
//存放点的坐标
struct Point{
int x;
int y;
};
queue <struct Point> q;
//打印图形
void prt(int m, int n){
int i,j;
for(i = 1; i <= m; i++){
for(j = 1; j <= n; j++){
printf("%2d", a[i][j]);
}
printf("\n");
}
return;
}
void BFS(int i, int j){
int ni, nj; //新的点的坐标
int dx[4] = {-1, 1, 0, 0}; //四个拓展填充的方向
int dy[4] = {0, 0, -1, 1};
struct Point p;
p.x = i;
p.y = j;
q.push(p); //队首入队
while(!q.empty()){
p = q.front();
q.pop();
i = p.x;
j = p.y; //队首出队
if(a[i][j] == 0){
a[i][j] = 1;
for(int k = 0; k <= 3; k++){ //探索四个方向
ni = i+dx[k];
nj = j+dy[k]; //新的坐标
if(ni >= 1 && ni <= m &&
nj >= 1 && nj <= n &&
a[ni][nj] == 0){ //判断是否越界或者延伸到1
p.x = ni;
p.y = nj;
q.push(p);
}
}
}
}
return;
}
int main(){
int i = 1,j = 1;
char c;
freopen("D:\\in.txt","r",stdin);
sum = 0;
c = getchar();
while(c != EOF){ //end of file
if(c != ' '){ //去空格
if(c != '\n'){
a[i][j] = c-'0';
sum = sum+1;
j = j+1;
}
else{ //下一行
n = j-1;
i = i+1;
j = 1;
}
}
c = getchar();
}
m = sum/n;
prt(m, n);
printf("——————————\n");
//对四条最外围的边进行广度优先探索
for(j = 1; j <= n; j++){
BFS(1, j);
BFS(m, j);
}
for(i = 1; i <= m; i++){
BFS(i, 1);
BFS(i, n);
}
prt(m, n);
for(i = 1; i <= m; i++){
for(j = 1; j <= n; j++){
if(a[i][j] == 0)
ans++;
}
}
cout <<"围成的面积为:"<<ans<<endl;
return 0;
}
代码运行效果如下: