为了让搜索的思路更加清晰,再来尝试另一个例子,先看题。
【题目描述】
小哼通过特殊方法得到了一张不完整的钓鱼岛航拍地图。钓鱼岛由一个主岛和一些附属岛屿组成,小哼决定去钓鱼岛探险,用二维矩阵代表钓鱼岛的航拍地图,图中数字表示海拔,0表示海洋,1-9都表示陆地。小哼的飞机将会降落在一个点(该点不在海洋上),现在需要计算小哼降落点所在岛屿的面积(即有多少个格子)。注意此处我们把与小哼降落点上下左右相连接的陆地视为同一岛屿。
【输入】
首先,第一行输入4个整数为n,m,startx,starty,分别表示地图的行和列,以及降落的初始坐标。
接下来的n行m列为地图。
【输出】
小哼降落点所在岛屿有多少格子数。
样例输入
10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0
样例输出
38
搞清楚题目之后会发现,这个题很明显可以用搜索解题,既可以用广度搜索,也可以用深度搜索。
广度搜索
解题思路
可以从起点开始广度搜索,每个点需要上下左右四个方向扩展,然后判断扩展的点是否大于0,然后满足则加入队列,直到head>=tail,扩展结束。加入队列的元素总和就是小岛的面积。
代码如下:
#include<stdio.h>
//设置一个结构体,表示扩展的横坐标和纵坐标
struct node
{
int x;
int y;
};
int main()
{
struct node k[2550];
int i,j,n,m,startx,starty,sum=0;
int a[50][50],book[50][50]={0};
int next[4][2]={0,1,0,-1,1,0,-1,0};//方向数组
//分别表示向右走,向左走,向下走,向上走
scanf("%d %d %d %d",&n,&m,&startx,&starty);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
//输入地图
}
}
int head=1,tail=1;
k[tail].x=startx;
k[tail].y=starty;
book[startx][starty]=1;
sum++;
tail++;
//当前的点扩展结束后,要tail++,继续下一个扩展点
int tx,ty;
while(head<tail)
{
for(i=0;i<4;i++)
{
//计算下一点的坐标
tx=k[head].x+next[i][0];
ty=k[head].y+next[i][1];
if(tx<1||tx>n||ty<1||ty>m)
continue;
if(a[tx][ty]!=0&&book[tx][ty]==0)
{
k[tail].x=tx;
k[tail].y=ty;
//如果满足条件,就把该点加入队列
book[tx][ty]=1;
sum++;
tail++;
}
}
head++;
//当一个点扩展结束时,才进行下一个点,此时head++
}
printf("%d\n",sum);
return 0;
}
深度搜索
解题思路
从起点开始,把每一个可以经过的点标记(可以经过的点在陆地上),然后统计标记的点的个数,总和就是所求的岛屿的面积。
代码如下:
#include<stdio.h>
int book[51][51];//标记的点就是陆地,输出结果是book数组里面元素之和
int a[51][51];//地图
int n,m;
//深度搜索函数
void dfs(int x,int y)
//它的作用是判断扩展的点是否为陆地
//并接着扩展
{
int i,j,tx,ty;
int next[4][2]={0,1,0,-1,1,0,-1,0};//方向数组
//分别表示向右走,向左走,向下走,向上走
for(i=0;i<4;i++)
{
tx=x+next[i][0];
ty=y+next[i][1];
if(tx<1||tx>n||ty<1||ty>m)
continue;
if(book[tx][ty]==0&&a[tx][ty]!=0)
{
book[tx][ty]=1;//如果是陆地,用book标记
dfs(tx,ty);//接着扩展
}
}
return ;
}
int main()
{
int sum=0,i,j,startx,starty;
scanf("%d %d %d %d",&n,&m,&startx,&starty);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
//输入地图
}
}
book[startx][starty]=1;//别忘了第一个点也要标记
dfs(startx,starty);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
sum=sum+book[i][j];//求出陆地面积
}
}
printf("%d\n",sum);
return 0;
}
总结
做题的时候老是把起点的标记(book[startx][starty]=0)丢下,这个题目丢下这个步骤会使程序出错。广度搜索会出错,因为sum多了一次自增运算。
深度搜索似乎不会出错,但是当这座岛面积为1时,忘记起点的标记就会出错。如果深度搜索统计面积计算方法与上述代码中广度搜索相同(用sum++),结果会与广度搜索错误的原因相同。
但是就算运行的结果是对的,也不应该忽略细节。