下面显示的解决方案(作为 python 程序)在 time 中运行O(n lg*(n))
,其中lg*(n)
几乎恒定的迭代日志函数通常与不相交集森林中的联合操作相关联。
在第一次遍历所有单元格时,程序使用名为makeset(), findset(), link(),
and的例程创建一个不相交集森林,union()
正如 Cormen/Leiserson/Rivest 第一版第 22.3 节(不相交集森林)中所解释的那样。在以后通过单元格时,它会计算每个不相交森林的成员数量,检查深度等。第一次通过及时运行O(n lg*(n))
,随后通过及时运行,O(n)
但通过简单的程序更改,一些通过可以运行O(c)
或O(b)
运行c 个洞穴,总共有 b 个细胞。
请注意,下面显示的代码不受上一个答案中包含的错误的影响,其中上一个答案的伪代码包含该行
if (size==0 and depth!=0) IsolatedCaveCount++
该行中的错误是与地表相连的洞穴可能有地下上升分支,这另一个答案会错误地添加到其孤立洞穴的总数中。
下面显示的代码产生以下输出:(
Deepest: 5 Largest: 22 Isolated: 3
请注意,图中显示的 24 的计数应该是 22,从 4+9+9。)
v=[0b0000010000000000100111000, # Cave map
0b0000000100000110001100000,
0b0000000000000001100111000,
0b0000000000111001110111100,
0b0000100000111001110111101]
nx, ny, nz = 5, 5, 5
inlay, ncells = (nx+1) * ny, (nx+1) * ny * nz
masks = []
for r in range(ny):
masks += [2**j for j in range(nx*ny)][nx*r:nx*r+nx] + [0]
p = [-1 for i in range(ncells)] # parent links
r = [ 0 for i in range(ncells)] # rank
c = [ 0 for i in range(ncells)] # forest-size counts
d = [-1 for i in range(ncells)] # depths
def makeset(x): # Ref: CLR 22.3, Disjoint-set forests
p[x] = x
r[x] = 0
def findset(x):
if x != p[x]:
p[x] = findset(p[x])
return p[x]
def link(x,y):
if r[x] > r[y]:
p[y] = x
else:
p[x] = y
if r[x] == r[y]:
r[y] += 1
def union(x,y):
link(findset(x), findset(y))
fa = 0 # fa = floor above
bc = 0 # bc = floor's base cell #
for f in v: # f = current-floor map
cn = bc-1 # cn = cell#
ml = 0
for m in masks:
cn += 1
if m & f:
makeset(cn)
if ml & f:
union(cn, cn-1)
mr = m>>nx
if mr and mr & f:
union(cn, cn-nx-1)
if m & fa:
union(cn, cn-inlay)
ml = m
bc += inlay
fa = f
for i in range(inlay):
findset(i)
if p[i] > -1:
d[p[i]] = 0
for i in range(ncells):
if p[i] > -1:
c[findset(i)] += 1
if d[p[i]] > -1:
d[p[i]] = max(d[p[i]], i//inlay)
isola = len([i for i in range(ncells) if c[i] > 0 and d[p[i]] < 0])
print "Deepest:", 1+max(d), " Largest:", max(c), " Isolated:", isola