What's the fastest way to find deepest path in a 3D array?

后端 未结 4 2272
遇见更好的自我
遇见更好的自我 2021-02-14 15:34

I\'ve been trying to find solution to my problem for more than a week and I couldn\'t find out anything better than a milion iterations prog, so I think it\'s time to ask someon

4条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-02-14 15:57

    The solution shown below (as a python program) runs in time O(n lg*(n)), where lg*(n) is the nearly-constant iterated-log function often associated with union operations in disjoint-set forests.

    In the first pass through all cells, the program creates a disjoint-set forest, using routines called makeset(), findset(), link(), and union(), just as explained in section 22.3 (Disjoint-set forests) of edition 1 of Cormen/Leiserson/Rivest. In later passes through the cells, it counts the number of members of each disjoint forest, checks the depth, etc. The first pass runs in time O(n lg*(n)) and later passes run in time O(n) but by simple program changes some of the passes could run in O(c) or O(b) for c caves with a total of b cells.

    Note that the code shown below is not subject to the error contained in a previous answer, where the previous answer's pseudo-code contains the line
    if (size==0 and depth!=0) IsolatedCaveCount++
    The error in that line is that a cave with a connection to the surface might have underground rising branches, which the other answer would erroneously add to its total of isolated caves.

    The code shown below produces the following output:
    Deepest: 5 Largest: 22 Isolated: 3
    (Note that the count of 24 shown in your diagram should be 22, from 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
    

提交回复
热议问题