递归探测算法的实现
迷茫童鞋的阅读指南
该项目的详细描述和算法的具体说明
请参见前一篇 Project2 Percolation in Grids 网格渗透
本人给出了percolation_provided.py的函数说明目前已完成水波探测算法的实现
该算法的关键是实现explore函数中递归,及percolation_recursive对explore的初始调用。
Step1:
国际惯例导入提供的函数:from percolation_provided import *
先考虑percolation_recursive函数,参数和前面的水波算法函数一样,定义为:percolation_recursive(input_grid, trace=True, short=False)
Step2:
老样子,还是生成一个flow_grid网格。
size = len(input_grid)
flow_grid = grid(size, -1)
flow_grid = grid(size, -1)
Step3:
为explore函数提供一个初始的开始状态,从第一行开始,遍历每个位置。
#start exploration from each space in top (zeroth) row
for col in range(size):
if explore(input_grid, flow_grid, 0, col, trace, short):
return flow_grid, True
for col in range(size):
if explore(input_grid, flow_grid, 0, col, trace, short):
return flow_grid, True
Step4:
设计这个explore函数,还是比较头疼的。关键是要考虑到如何在这里面实现递归,我们从项目中的描述来分解这个问题:
假设一个单元与[i][j]相邻,流能够到达(i也可以为第一行),input_grid[i][j]=0,flow_grid[i][j]=-1。这意味着没有流到达过[i][j]位置,该位置不阻塞,且流能够从相邻的位置到达它。我们通过设置flow_grid[i][j]=*来记录流能够到达位置[i][j]。然后,函数explore考虑流能够到达的[i][j]的相邻位置,每个位置探测一次。对于每个这样的相邻位置,explore将其相邻位置看作行列索引,并使用一次递归调用。在递归调用结束后,上面的explore的初始状态保持不变。
那么就是:
1.对于位置[i][j]的相邻位置,如果是开放且未被访问,使用递归调用
2.对于每次探索到的位置设置flow_grid[i][j]=*来标记,保证只探测一次
3.由percolation_recursive传来的值,需要判断该位置是否是开放的,是的话标记为'*'
4.算法是全部执行完才退出的,返回值为None,为了快速结束算法并确定是否渗透,我们使用传入的short布尔值变量作为判断,只要当前处理的位置处于最后一行,就退出返回True
具体实现如下:
Look Code
def explore(input_grid, flow_grid, row, col, trace, short):
"""Explore the grid, marking unblocked cells as full as they are explored"""
size = len(input_grid)
if input_grid[row][col] == 0:
flow_grid[row][col] = '*'
if trace:
visualize(flow_grid, input_grid)
rate(2)
#explore neighboring cells
if short:
if row + 1 == size:
return True
# Look down
if row + 1 < size:
if input_grid[row+1][col] == 0 and flow_grid[row+1][col] == -1:
percolation_recursive_explore(input_grid, flow_grid,
row+1, col, trace, short)
# Look right
if col + 1 < size:
if input_grid[row][col+1] == 0 and flow_grid[row][col+1] == -1:
percolation_recursive_explore(input_grid, flow_grid,
row, col+1, trace, short)
# Look left
if col - 1 >= 0:
if input_grid[row][col-1] == 0 and flow_grid[row][col-1] == -1:
percolation_recursive_explore(input_grid, flow_grid,
row, col-1, trace, short)
# Look up
if row - 1 >= 0:
if input_grid[row-1][col] == 0 and flow_grid[row-1][col] == -1:
percolation_recursive_explore(input_grid, flow_grid,
row-1, col, trace, short)
"""Explore the grid, marking unblocked cells as full as they are explored"""
size = len(input_grid)
if input_grid[row][col] == 0:
flow_grid[row][col] = '*'
if trace:
visualize(flow_grid, input_grid)
rate(2)
#explore neighboring cells
if short:
if row + 1 == size:
return True
# Look down
if row + 1 < size:
if input_grid[row+1][col] == 0 and flow_grid[row+1][col] == -1:
percolation_recursive_explore(input_grid, flow_grid,
row+1, col, trace, short)
# Look right
if col + 1 < size:
if input_grid[row][col+1] == 0 and flow_grid[row][col+1] == -1:
percolation_recursive_explore(input_grid, flow_grid,
row, col+1, trace, short)
# Look left
if col - 1 >= 0:
if input_grid[row][col-1] == 0 and flow_grid[row][col-1] == -1:
percolation_recursive_explore(input_grid, flow_grid,
row, col-1, trace, short)
# Look up
if row - 1 >= 0:
if input_grid[row-1][col] == 0 and flow_grid[row-1][col] == -1:
percolation_recursive_explore(input_grid, flow_grid,
row-1, col, trace, short)
Step5:
回到前面的函数,如果short被定义为False。那么无论最后是否发生渗透,explore函数表面上看是void类型的,其实会返回一个值None。那么就需要在函数体加上一段渗透判断。判断依据就是flow_grid的最后一行是否有元素的值为*
for col in range(size):
if flow_grid[size-1][col] == '*':
return flow_grid, True
if flow_grid[size-1][col] == '*':
return flow_grid, True
最后这里是完整的代码:
I’m Code
1 #! /usr/bin/env python
2 from visual import rate
3 from percolation_provided import *
4
5 def percolation_recursive(input_grid, trace=True, short=False):
6 """
7 Determine whether or not a grid percolates, and which cells are filled.
8 Like before, short is True if you want the algorithm to stop immediately
9 when it percolates, rather than exploring the entire grid.
10 """
11 size = len(input_grid)
12 flow_grid = grid(size, -1)
13
14 #start exploration from each space in top (zeroth) row
15 for col in range(size):
16 if explore(input_grid, flow_grid, 0, col, trace, short):
17 return flow_grid, True
18
19 #check last (size-1'th) row for full spaces
20 for col in range(size):
21 if flow_grid[size-1][col] == '*':
22 return flow_grid, True
23
24 #no full spaces in bottom row; doesn't percolate
25 return flow_grid, False
26
27 def explore(input_grid, flow_grid, row, col, trace, short):
28 """Explore the grid, marking unblocked cells as full as they are explored"""
29 size = len(input_grid)
30 if input_grid[row][col] == 0:
31 flow_grid[row][col] = '*'
32
33 if trace:
34 visualize(flow_grid, input_grid)
35 rate(2)
36
37 #explore neighboring cells
38
39 if short:
40 if row + 1 == size:
41 return True
42
43 # Look down
44 if row + 1 < size:
45 if input_grid[row+1][col] == 0 and flow_grid[row+1][col] == -1:
46 percolation_recursive_explore(input_grid, flow_grid,
47 row+1, col, trace, short)
48 # Look right
49 if col + 1 < size:
50 if input_grid[row][col+1] == 0 and flow_grid[row][col+1] == -1:
51 percolation_recursive_explore(input_grid, flow_grid,
52 row, col+1, trace, short)
53
54 # Look left
55 if col - 1 >= 0:
56 if input_grid[row][col-1] == 0 and flow_grid[row][col-1] == -1:
57 percolation_recursive_explore(input_grid, flow_grid,
58 row, col-1, trace, short)
59
60 # Look up
61 if row - 1 >= 0:
62 if input_grid[row-1][col] == 0 and flow_grid[row-1][col] == -1:
63 percolation_recursive_explore(input_grid, flow_grid,
64 row-1, col, trace, short)
2 from visual import rate
3 from percolation_provided import *
4
5 def percolation_recursive(input_grid, trace=True, short=False):
6 """
7 Determine whether or not a grid percolates, and which cells are filled.
8 Like before, short is True if you want the algorithm to stop immediately
9 when it percolates, rather than exploring the entire grid.
10 """
11 size = len(input_grid)
12 flow_grid = grid(size, -1)
13
14 #start exploration from each space in top (zeroth) row
15 for col in range(size):
16 if explore(input_grid, flow_grid, 0, col, trace, short):
17 return flow_grid, True
18
19 #check last (size-1'th) row for full spaces
20 for col in range(size):
21 if flow_grid[size-1][col] == '*':
22 return flow_grid, True
23
24 #no full spaces in bottom row; doesn't percolate
25 return flow_grid, False
26
27 def explore(input_grid, flow_grid, row, col, trace, short):
28 """Explore the grid, marking unblocked cells as full as they are explored"""
29 size = len(input_grid)
30 if input_grid[row][col] == 0:
31 flow_grid[row][col] = '*'
32
33 if trace:
34 visualize(flow_grid, input_grid)
35 rate(2)
36
37 #explore neighboring cells
38
39 if short:
40 if row + 1 == size:
41 return True
42
43 # Look down
44 if row + 1 < size:
45 if input_grid[row+1][col] == 0 and flow_grid[row+1][col] == -1:
46 percolation_recursive_explore(input_grid, flow_grid,
47 row+1, col, trace, short)
48 # Look right
49 if col + 1 < size:
50 if input_grid[row][col+1] == 0 and flow_grid[row][col+1] == -1:
51 percolation_recursive_explore(input_grid, flow_grid,
52 row, col+1, trace, short)
53
54 # Look left
55 if col - 1 >= 0:
56 if input_grid[row][col-1] == 0 and flow_grid[row][col-1] == -1:
57 percolation_recursive_explore(input_grid, flow_grid,
58 row, col-1, trace, short)
59
60 # Look up
61 if row - 1 >= 0:
62 if input_grid[row-1][col] == 0 and flow_grid[row-1][col] == -1:
63 percolation_recursive_explore(input_grid, flow_grid,
64 row-1, col, trace, short)
None