继续学习深搜

上一次我经历了我与深搜的第一次。理解了之后感觉很有成就感。

但是,那仅仅是一部分。我对深搜还没有完全的理解。那么就下来,就再来一次。

(听说week4的第一题要用广搜而不是深搜,但是我打算先学会深搜。毕竟都是学习嘛。)

(深搜吃透了,广搜其实就好理解了)

那么先把这次研究的例题搞上去:

问题:GeoSurvComp地质调查公司负责探测地下石油储藏。 GeoSurvComp现在在一块矩形区域探测石油,并把这个大区域分成了很多小块。他们通过专业设备,来分析每个小块中是否蕴藏石油。如果这些蕴藏石油的小方格相邻,那么他们被认为是同一油藏的一部分。在这块矩形区域,可能有很多油藏。你的任务是确定有多少不同的油藏。

input: 输入可能有多个矩形区域(即可能有多组测试)。每个矩形区域的起始行包含m和n,表示行和列的数量,

1<=n,m<=100,如果m =0表示输入的结束,接下来是n行,每行m个字符。每个字符对应一个小方格,并且要么是’*’,代表没有油,要么是’@’,表示有油。

output: 对于每一个矩形区域,输出油藏的数量。两个小方格是相邻的,当且仅当他们水平或者垂直或者对角线相邻(即8个方向)。

 这个问题与之前的那个稍微复杂了一些。但是也不成问题。

上一个问题中,我们达到下一行之后,要先开始一个for循环。去遍历我们在这一行里面的所有情况。

我们抽象一下。再上一个题里面。我们每走一步就是进到下一个行。也就是说,我们的“步”就是行。

这个题呢?我们的每一步,就成了每一格油田了,我们的下一步是下一格油田。

然后呢?每一步之间是什么联系的呢?

上一个题目,当前步要先进行数字的选择才能进到下一步。这里也一样,这里是先要进行方向的选择,才能进到下一步。

二者有什么不同呢?

他们其实没什么不同。上一个的第一次调用是去找所有的组合,这次一的调用失去开辟每一个方向。其实二者都是不断地产生分支。但是这分支绝对不是同时产生的!如果用for循环所给的‘i“来表示我们的分支的话:

第一次:11111111111

第二次:11111111112

第三次:11111111121

就是这样。

原因就在于多个递归的出栈顺序是先进先出的。

okk

那么下面分析一下代码。

分析的话,我就放在代码里面的注释里了!

                                                            

 

#include <iostream>
using namespace std;
int m, n;
int sum = 0;
int judge(int x, int y);
int dfs(int x, int y);
int a[101][101];
int v[9][2] = { {0,0},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1.0},{-1,1} };
int main()
{
	cin >> m >> n;
	for (int i = 1; i <= m; i += 1)
	{
		for (int x = 1; x <= n; i += 1)
		{
			cin >> a[m][n];
		}
	}
	//	m行,n列
	for (int x = 1; x <= m; x += 1)
	{
		for (int y = 1; y <= n; y += 1)
		{
			if (dfs(x, y))
			{
				sum += 1;
			}
		}
	}
	cout << sum;
	return 0;
}
int judge(int x, int y)
{
	if (a[x][y] == '@'&&x<=100&&y<100)  //  这里用来形成油田的边界
	{
		
		return 1;
	}
	else
	{
		return 0;
	}
}
int dfs(int x, int y)
{
	if (judge(x, y))  //  注意,我们的深搜的程序必须在这个if里面,因为我们只要碰到不是油田的,就停止这一个分支
	{
		a[x][y] = '*';   // 以此来标记一个已经被统计过的油田
		//	上面这一步很重要这种格子地图遍历的关键
		//  走迷宫也是,我们走过了就不能再走了,这时候就要标记。
		//  大家想一下,为什么迷宫题走过了就不能再走了?原因在于避免重复统计
		//	下面想一下怎么去解决遍历方向的问题
		//   一共八个方向,很自然的就像想到,可以用一个for循环实现。也就是i从1到8;
		//	然后我想到了矩阵。刚学的。
		//  我们建立一个二维数组,代表了向8个方向走的话,x与y的变化
		//	就叫这个数组v吧。
		for (int i = 1; i <= 8; i += 1)
		{
			//  这时候我遇到了一个问题,那就是这个新的坐标应该定义在什么地方?
			//  想一想,这个新的坐标只有接下来的调用需要用,所以在for循环小节里面定义就好
			int nx, ny;
			nx = x + v[i][0];
			ny = y + v[i][1];
			//	选择之后进行递归的调用
			//  不要脸地把任务交给无数个dfs
			dfs(nx, ny);
			return 1;  //  这就是深搜地精华!这是程序一脚踏进去深不见底的调用以后,终于爬出来以后的样子
		}
	}
	return 0;  //  就像前面说的一样,如果这个起步的点本身就不是油田的话,那就直接理都不理,sum也不会+1
}

 

okk

就到这里啦 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值