【代码超详解】UVA 572 Oil Deposits 油田

一、题目描述

GeoSurvComp 公司负责勘探地下的石油存在情况。公司在作业时总是把矩形区域分成一个个方格,然后独立分析各个方格,探测地下是否存在石油。
输入多个测试样例。每个样例的第一行是两个整数 m 和 n 代表区域被分成 m 行 n 列(0 < m, n <= 100)的小方格。接下来 m 行输入 n 个字符,表示每一格的勘探结果, 星号表示没有石油,@ 表示存在石油。
如果 @ 能跟周围八个方块直接连在一起,就将这些 @ 标记的含有石油的区域视为一片油田。对每个测试用例,输出油田数量。

二、算法分析说明与代码编写指导

基本思路:
依次查找每一格,如果标记为 @ 就查找周围 8 个格。周围 8 个格中的任意一个格仍然有 @ 就继续查找该格周围的 8 个格。
可以看出,将查找周围 8 个格的过程写成函数并递归调用比较合适。
除了要用专门的二维数组 grid[101][101] 标记存在石油的情况以外,还需要一个相同大小的二维数组 id[101][101] 来记录每个连通区域的 ID 。这是因为如果只标记是否存在石油,那么当查找到某个 @ 并查找与其连通的 @ 的时候,并不能得知这些 @ 连通的是已经查找过的整片油田还是新的油田,所以需要对已找到的部分分配唯一的标识符方便计数。
搜索过程中,因为是调用递归函数搜索的,所以一定要增加额外的限制条件,避免无限递归。为了防止陷入死循环并减少搜索次数,需要添加判断。仅该方格是 @ 符号时才进行搜索并标记 ID 。对其周围 8 个方格同理。而且如果已经标记了 ID(从 1 开始,未被标记过的存在石油的小块的 ID 都记为零),该格就不再搜索。这样不但可以减少搜索次数,对查找过程中遇到的已经确定是油田的区域(即已有不为零的 ID 的区域)不用再一格一格去判断,还可以避免如下情形的死循环:查找到某个 @ ,在查找周围 8 个格的时候如果也查找到 1 个 @ ,那么这个 @ 的周围 8 个格中肯定又包含原来的 @ ,于是在查找新的 @ 的周围 8 格的过程中又会找到这个原来的 @ 并继续查找,如此往复。
另外,为了避免越界,还需要在查找的边界所在的行数或列数小于零,或者行数大于等于 m(从第 0 行开始对网格编号),或者列数大于等于 n 的时候直接停止继续深入搜索。
这里面有个小技巧,在主程序里初次调用搜索函数 SearchSur 时,传入的第三个参数就是当前的 ID,在传入前就从 0 开始增加,增加以后再传入,每次在 main() 里调用时这个参数都增加 1 。这个 ID 即为已探明的油田的编号(从 1 开始)。而在函数内再调用时,传入的 ID 就保持最开始的递归调用时传入的 ID 而不增加,这就让一个连通区域的所有 @ 对应的位置都被标记为同一个 ID 。
在输入新的样例前,都要清空已有的记录

三、AC 代码(0 ms)

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#pragma warning(disable:4996)
char m, n; unsigned 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值