2小时。

先是是纠错,通过对代码运行过程的测试。发现是变量打错。以及录入地图❌。

重构练习题,改使用while..end代替for in.

⚠️ : 在while(k <= n)中如果用到next,为了不陷入死♻️,注意条件的判断, 一般要在next前k += 1。

题:爆炸小子炸怪兽

代码:

1.广度优先搜索

设定一个点,先访问这个点的每个周边点,然后再扩展到每个周边点的还未访问的点。

代码:使用队列(栈)。

# 地图
map = [
["#","#","#","#","#","#","#","#","#","#","#","#","#"],
["#","g","g",".","g","g","g","#","g","g","g",".","#"],
["#","#","#",".","#","g","#","g","#","g","#","g","#"],
["#",".",".",".",".",".",".",".","#",".",".","g","#"],
["#","g","#",".","#","#","#",".","#","g","#","g","#"],
["#","g","g",".","g","g","g",".","#",".","g","g","#"],
["#","g","#",".","#","g","#",".","#",".","#",".","#"],
["#","#","g",".",".",".","g",".",".",".",".",".","#"],
["#","g","#",".","#","g","#","#","#",".","#","g","#"],
["#",".",".",".","g","#","g","g","g",".","g","g","#"],
["#","g","#",".","#","g","#","g","#",".","#","g","#"],
["#","g","g",".","g","g","g","#","g",".","g","g","#"],
["#","#","#","#","#","#","#","#","#","#","#","#","#"]
]
# 地图副本book,用于标记走过的点。用compact复制出新的array。
# 因为不能嵌套复制。需要用map
book = map.map{|item| item.compact }
# 输出地图(对输出结果进行美化)
i = 0
n = map.size
n.times do |x|
print "#{x} "
end
print "\n"
while i < n
j= 0
while j < n
case map[i][j]
when "#"
print "◼︎ "
when "g"
print "☿ "
when "."
print "  "
end
j += 1
end
print "\n"
i += 1
end
# 杀怪统计Method
def getnum(startx, starty, map)
# 四个方向各自统计杀怪数,加到sum中
sum = 0
x = y = 0
# 向下,遇到“#”,停止。(爆炸受阻)
x = startx
y = starty
while map[x][y] != "#"
if map[x][y] == "g"
sum += 1
end
x += 1
end
# 上
x = startx
y = starty
while map[x][y] != "#"
if map[x][y] == "g"
sum += 1
end
x -= 1
end
# 右
x = startx
y = starty
while map[x][y] != "#"
if map[x][y] == "g"
sum += 1
end
y += 1
end
# 左
x = startx
y = starty
while map[x][y] != "#"
if map[x][y] == "g"
sum += 1
end
y -= 1
end
return sum
end
# 设定开始起点位置
print "请输入起点坐标x:\n"
startx = gets.to_i
print "请输入起点坐标y:\n"
starty = gets.to_i
# wide first search (核心)
x = []
y = []
# 指针head , tail(队列最后一位的后面空白处)
head = 0
tail = 1
x[head] = startx
y[head] = starty
# 坐标点周边的四个方向,目的是访问相邻的4个点
next_direction = [
[0, 1],#右
[1, 0],#下
[0,-1],#左
[-1,0] #上
]
# 统计最大击杀
kill_max = 0
max_x = max_y = 0
# 边界的判断
nx = map[0].size - 2
ny = map.size - 2
# 大循环,wide first search
while head < tail
# 每个坐标点周边点的情况判定。
k = 0
while k <= 3
tx = x[head] + next_direction[k][0]
ty = y[head] + next_direction[k][1]
# 界限
if tx < 1 || tx > nx || ty <1 || ty > ny
# k += 1必不可少,否则会死循环。用for语法的话可以避免。
      k += 1
next
end
# 判断是否是平地,而且没有走过
if map[tx][ty] == "." && book[tx][ty] == "."
# 在地图上标记已经走过
book[tx][ty] = "X"
  x << tx
      y << ty
# 队列尾巴的后一位,用于判断是否结束大循环
  tail += 1
# 统计杀怪数量,调用Method
sum_kill = getnum(tx, ty, map)
if sum_kill > kill_max
kill_max = sum_kill
max_x = tx
max_y = ty
end
end
k += 1
end
# 头部指针前移动
  head += 1
end
p "最大击杀#{kill_max}"
p "坐标:(#{max_x},#{max_y})"

2.深度优先搜索

核心,设定一个边界(目标),延一个方向走到满足条件的极限,然后回朔换方向走,一旦不满足条件就回朔。只关注当下

代码: dfs()嵌套 + 界限

# 地图
$map = [
["#","#","#","#","#","#","#","#","#","#","#","#","#"],
["#","g","g",".","g","g","g","#","g","g","g",".","#"],
["#","#","#",".","#","g","#","g","#","g","#","g","#"],
["#",".",".",".",".",".",".",".","#",".",".","g","#"],
["#","g","#",".","#","#","#",".","#","g","#","g","#"],
["#","g","g",".","g","g","g",".","#",".","g","g","#"],
["#","g","#",".","#","g","#",".","#",".","#",".","#"],
["#","#","g",".",".",".","g",".",".",".",".",".","#"],
["#","g","#",".","#","g","#","#","#",".","#","g","#"],
["#",".",".",".","g","#","g","g","g",".","g","g","#"],
["#","g","#",".","#","g","#","g","#",".","#","g","#"],
["#","g","g",".","g","g","g","#","g",".","g","g","#"],
["#","#","#","#","#","#","#","#","#","#","#","#","#"]
]
# 地图副本book,用于标记走过的点。用compact复制出新的array。
# 因为不能嵌套复制。需要用map
$book = $map.map{|i| i.compact }
# 输出地图(对输出结果进行美化)
i = 0
nx = $map.size
ny = $map.first.size
nx.times do |n|
if n >=10
print "#{n}"
else
print "#{n} "
end
end
print "\n"
while i < nx
j = 0
while j < ny
case $map[i][j]
when "#"
print "◼︎ "
when "g"
print "☿ "
when "."
print "  "
end
j += 1
end
print "#{i}\n"
i += 1
end
# 杀怪统计Method
def getnum(startx, starty)
# 四个方向各自统计杀怪数,加到sum中
sum = 0
x = y = 0
# 向下,遇到“#”,停止。(爆炸受阻)
x = startx
y = starty
while $map[x][y] != "#"
if $map[x][y] == "g"
sum += 1
end
x += 1
end
# 上
x = startx
y = starty
while $map[x][y] != "#"
if $map[x][y] == "g"
sum += 1
end
x -= 1
end
# 右
x = startx
y = starty
while $map[x][y] != "#"
if $map[x][y] == "g"
sum += 1
end
y += 1
end
# 左
x = startx
y = starty
while $map[x][y] != "#"
if $map[x][y] == "g"
sum += 1
end
y -= 1
end
return sum
end
#深度优先搜索。----------------------------
# 设定开始起点位置
print "请输入起点坐标x:\n"
startx = gets.to_i
print "请输入起点坐标y:\n"
starty = gets.to_i
# 统计最大击杀
$kill_max = 0
$max_x = $max_y = 0
def dfs(x,y)
# 计算杀敌总数。(深度优先搜索的边界)
sum = getnum(x,y)
if sum > $kill_max
$kill_max = sum
$max_x = x
$max_y = y
end
# 坐标点周边的四个方向,目的是访问相邻的4个点
next_direction = [
[0, 1],#右
[1, 0],#下
[0,-1],#左
[-1,0] #上
]
# 四个方向枚举
k = 0
while k <= 3
tx = x + next_direction[k][0]
ty = y + next_direction[k][1]
# 判断是否越界
if tx < 1 || tx > 11 || ty <1 || ty > 11
# k += 1必不可少,否则会死循环。用for语法的话可以避免。
k += 1
next
end
#判断是否围墙,或走过。
if $map[tx][ty] == "." && $book[tx][ty] == "."
$book[tx][ty] = "X"
      dfs(tx,ty)   #通过不断的深度嵌套,再通过回朔改变方向,来完成遍历每个点。
end
k += 1
end
end
dfs(startx,starty)
print "最大击杀:#{$kill_max}\n"
p "坐标(#{$max_x},#{$max_y})"

宝岛探险:

广度,深度,和上色。

给所有岛着色(深度):嵌套循环,遍历所有岛(大于0)并标记,着色(num,不同的岛用不同的数表示。)

# 地图,0代表海洋,1-9代表陆地及其海拔。
$map = [
[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]
]
# 飞机降落位置坐标。
startx = 0
starty = 0
# 复制一个全新的地图用于在图上做标记。
$book = $map.map { |e| e.compact }
# 用于给不同的到上不同的颜色
$map_color = $map.map { |e| e.compact  }
# 记录岛的面积
$sum = 0
# dfs方法 深度优先搜索。
def dfs(startx, starty,num)
# 方向坐标,按照右,下,左,上顺序排列。
next_direction = [
[0, 1],
[1, 0],
[0,-1],
[-1,0]
]
# 边界,本题不需要
i = 0
for i in 0..3 do
tx = startx + next_direction[i][0]
ty = starty + next_direction[i][1]
# 判断是否越界
if tx < 0 || tx > 9 || ty < 0 || ty > 9
next
end
# 判断是否为没发现的陆地
    if $map[tx][ty] > 0 && $book[tx][ty] != "x"
      $book[tx][ty] = "x"
      $sum += 1
      $map_color[tx][ty] = num #陆地染色为num
      dfs(tx,ty,num)
    end
end
end
num = 0 #不同小岛的编号
# 遍历所有陆地(>0),每块陆地,一旦走过就$book标记“x”
i = j = 0
for i in 0..9 do
for j in 0..9 do
    if $map[i][j] > 0 && $book[i][j] != "x"
num -= 1
      $map_color[i][j] = num  #陆地染色为num
  $book[i][j] = "x"

$sum += 1

#调用函数,相邻的陆地都会染色相同num
dfs(i,j,num)
end
end
end
p "岛的面积#{$sum}"
$map_color.each do |x|
x.each do |y|
printf("%3s",y)
end
print "\n"
end
$book.each do |x|
x.each do |y|
if y == "x"
print "❌ "
else
print "#{y} "
end
end
print "\n"
end


水管工

深度优先搜索实现。

⚠️ :判断每个管子的进水口inflow,用dfs方法时,除了x,y坐标参数,还有inflow进水口参数。每一次调用dfs(x,y,inflow)都是下一个管道,此时的出水口,是下一个的进水口,如果用东南西北表示,要注意改成进水口方向。例子:如果当前管子的出水口是东,那么下一个管子的进水口就是西。

$map = [
[5,3,5,3],
[1,5,3,0],
[2,3,5,1],
[6,1,1,5],
[1,5,5,5]
]
$book = $map.map { |e| e.compact }
# 用1-6分别表示水管的6种排列形式。4个弯管,2个直管
# n,m+1时候停止
# 参数inflow为进水方向。W进水口在西,N进水口在上,E进水口在right,S进水口在下。
inflow = ""
# 判断是否成功出水
$flag = "no"
#用于记录路径,栈:后进的先出,ruby用pop方法,去掉数组最后一个,也可以加个指针
$x = []
$y = []
def dfs(x, y, inflow)
p "开始dfs"
# 界限:停止dfs得出结果
# 判断水流是否走出地图,看地图东南角的边界。
if x == 4 && y == 4
$flag = "yes"
len = $x.size #队列的长度,然后输出连个数组x,y
len.times do |n|
printf("(%d,%d)->",$x[n],$y[n])
end
return
end
# 判断是否边界
if x < 0 || x > 4 || y < 0 || y > 3
return
end
# 判断是否已经标记了
if $book[x][y] == "Y"
return
end
$book[x][y] = "Y"
# 当前坐标入栈
$x << x
$y << y
print "#{$x}\n#{$y}.\n"
# 当前水管是直管的情况 5表示东西走向,6表示南北走向。
if $map[x][y] >= 5 && $map[x][y] <= 6
# "直管"
case inflow
when "W" #水从西进,下一个管道也是从西进,第三个参数是进水方向
dfs(x, y+1, "W")
when "N"
dfs(x+1, y , "N")
when "E"
dfs(x, y-1, "E")
when "S"
dfs(x-1, y ,"S")
end
end
# 当前水管是弯管的情况 1表示东北口,2表示东南口,3表示西南口,4表示西北口
if $map[x][y] >= 1 && $map[x][y] <= 4
#  "弯管"
case inflow
when "N" #当水从北流入,弯管只有两种流出结构,但inflow参数是进水方向。
dfs(x, y+1, "W") #下一个管,和进水方向,不要混淆出水方向。
dfs(x, y-1, "E")
when "E" #当水从东流入,弯管只会两种流出方向,N,S
dfs(x-1, y, "S")
dfs(x+1, y, "N")
when "S"
dfs(x, y+1, "W")
dfs(x, y-1 ,"E")
when "W"
dfs(x-1, y, "S")
dfs(x+1, y, "N")
end
end
# 在dfs方法不再深度后,执行下面代码,取消标记 。
# 目的:用于回溯,产生其他方案
$book[x][y] = "N"
# 栈后进先出,去掉不合格的
$x.pop
$y.pop
return
end
dfs(0,0,"W")
if $flag == "yes"
print "找到出水方案"
else
print "没找到出水方案"
end

问题处理:

第一问:我在整体代码最后希望输出管道路径,代码如下:

10.times do |n|
$map[$x[n]][$y[n]] = "X"
end
$map.each do |x|
print "#{x}\n"
end

出错❌: no implicit conversion from nil to integer (TypeError)

试❌:加入代码p $x 发现得到[],竟然是空数组,难怪错误提示是nil to integer.

因为,dfs方法结束后 $x,$y已经清空。变为空数组 。可以放到dfs方法中的判断水流是否走出地图的if..end中,注意单独复制一个地图用于储存路径,$route = $map.map{|e|e.compact}

第二问: 代码正确得到结果,但是改变地图结构,就不能得到正确结构。

出错❌ 代码:

# 目的:用于回溯,产生其他方案

$book[x][y] == "N"

分析:

粗心多写了一个=。导致不能正确回朔。之前的代码正确也是瞎猫碰死耗子。

转载于:https://www.cnblogs.com/chentianwei/p/8460069.html

2018-2-22 《啊哈,算法》再练习广度优先搜索,题:炸怪兽, 2-23改用深度优先搜索。宝岛探险(广度,深度,及地图着色)2-24水管工游戏,2-25测试水管工代码...相关推荐

  1. 《阿哈!算法》4-1不撞南墙不回头 4-2 解救小哈——深度优先搜索

    深度优先搜索关键在于解决"当下该如何做".至于"下一步如何做"则与当下该如何做"是一样的. 深度优先搜索模型: void dfs(int step){ ...

  2. 我才22岁,我再玩一年又能怎么样?等我23岁的时候,一定给你活出个人样

    (前排提示:红字提取文章主要内容) 种一棵树最好的时间是十年前,其次是...对不起,没有其次! 一_前言 想先问你一个问题:你今年多大了? 如果你还不到22岁,那么先恭喜你,你可以慢慢种树. 如果你已 ...

  3. python反恐精英代码类似的编程_敲代码学Python:CS188之实现深度优先搜索

    先上运行代码后的视频:人工智能导论之深度优先搜索演示https://www.zhihu.com/video/1173641673426378752深度优先搜索演示之大地图https://www.zhi ...

  4. 【图论算法】深度优先搜索的应用

    文章目录 深度优先搜索 无向图 双连通性 双连通以及割点的概念 找出图中割点的算法 一个例子 欧拉回路 认识欧拉回路 找出欧拉回路的算法 一个例子 有向图 查找强分支 dfs简单应用--部分和问题 深 ...

  5. 算法(6)深度优先搜索和广度优先搜索

    一.深度优先搜索(DFS) 主要思路: 从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底,不断递归重复此过程,直到所有的顶点都遍历 ...

  6. 啊哈算法之水管工游戏

    先给不同状态的水管编给号吧 跟走迷宫一样的,深搜,每个dfs里遍历水管的状态,如果当前状态和水管指向的下一个状态能连通就深搜过去直到走到终点为止 上代码吧,这个代码是加强版,支持了更多的水管的编号,以 ...

  7. 冰山立方体BUC算法(附测试集和完整代码)

    目录: 算法思路 算法实现 算法运行结果 一.算法思路 设想的算法分为三部分: 1.计算输入数据的维数.每个维的基数.每个维的取值个数以及每个维的取值. 2.设计一个函数,参数为一个列表,计算该列表在 ...

  8. 2018/01/22 爬虫日记

    20171024 ①导入自定义的模块(如类),需要在当前类作导入 类的引用声明,如self.tool = tool.Tool() 20171025 ①正则表达式:两个<><>之 ...

  9. Java学习笔记——从零开始(2018.04.22已更新)

    2018.04.08 --Java开发入门-- -计算机基本概念- •什么是计算机 计算机是一种能够按照程序运行,自动.高速处理海量数据的现代化智能电子设备.由硬件和软件所组成,没有安装任何软件的计算 ...

最新文章

  1. ssh 信息泄露 1 处,服务存在被爆破风险如何处理
  2. Django系列教程:三、动态视图和动态Url
  3. hdu1686 最大匹配次数 KMP
  4. 有关网页抓取问题的一些经验总结 - passover【毕成功的博客】 - 51CTO技术博客
  5. python3多进程写时拷贝_Python实现多进程的详解(附示例)
  6. Intellij IDEA调试
  7. antd vue 多个下拉 联动_Antd下拉选择,自动匹配功能的实现
  8. UVA - 10779 Collectors Problem
  9. 迪迦奥特曼“亲临”发布会!一加9R今日发布:价格成唯一悬念
  10. archLinux 安装拼音输入法
  11. 失业在家靠做PPT日赚800-1000元,有一门副业真的很重要!
  12. 最新高级JAVA架构师之路(价值3万元+年薪百万计划)
  13. win10计算机本地组策略编辑器,win10本地组策略编辑器打不开最佳解决方法
  14. 【哼歌检索】十大语音搜索应用服务
  15. 盘点阿里巴巴 34 个牛逼 GitHub 项目
  16. VMware 中Fedora系统连接网络问题!
  17. 计算机垃圾桶桌面,电脑桌面比垃圾桶还乱?一分钟轻松快速整理你的电脑桌面...
  18. Andriod 布局
  19. Ip地址基础--全篇无废话
  20. 那些年的自动驾驶仿真软件

热门文章

  1. 线性表顺序存储结构的基本操作(C++)
  2. 跑跑卡丁车手游测试开启:PK腾讯同款QQ飞车谁能赢?
  3. 有限元仿真分析误差来源之材料参数设置,小心为妙!
  4. gmail账号找回_如何找回旧的Gmail
  5. 微信小游戏:Cocos Creator《守卫竹林》线上游戏源码资源分享
  6. i513500h和i912900h差距 酷睿i5 13500h和i9 12900h对比
  7. 您的计算机出现了页面配置问题,由于启动计算机时出现了页面配置问题【处置方案】...
  8. 动态规划 之 零一背包
  9. 1049 最后一块石头的重量 II(零一背包问题)
  10. 毕业设计-基于深度学习的花卉识别分类