搜索的实例——宝岛探险

为了让搜索的思路更加清晰,再来尝试另一个例子,先看题。

【题目描述】

小哼通过特殊方法得到了一张不完整的钓鱼岛航拍地图。钓鱼岛由一个主岛和一些附属岛屿组成,小哼决定去钓鱼岛探险,用二维矩阵代表钓鱼岛的航拍地图,图中数字表示海拔,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++),结果会与广度搜索错误的原因相同。

但是就算运行的结果是对的,也不应该忽略细节。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明里灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值