Anyone knows an algorithm for finding “shapes” in 2d arrays?

后端 未结 5 1384
不思量自难忘°
不思量自难忘° 2021-02-04 08:25

Let\'s take this map, where \'#\' illustrates a taken square and \'.\' illustrates a free square:

1 . # # # . .
2 . # . . # .
3 # . . . . #
4 . # # # . .
5 . . . . .          


        
相关标签:
5条回答
  • 2021-02-04 08:35

    If you model this map as a graph, and each square is connected to its four neighbours, you can use a bridge finding algorithm to find the square you need.

    Note this model gives you several subgraphs to work with sometimes, so it might produce a number of false positives around the border, since adding a # there would certainly separate some nodes from the rest. To get around this, you could pad two levels of squares around the graph, so that no single # could separate a border node from the rest.

    @svick's comment inspired this method.

    0 讨论(0)
  • 2021-02-04 08:44

    If you can convert your problem to a graph, what you are looking for is to identify connected components. And if a connected component does not contain an edge that is the boundary edge, then you have found the region that needs to be filled.

    If I define the graph like this:

    G = (V, E)
    V = {r1, r2, r3, r4, r5, r6, c1, c2, c3, c4, c5, c6}
    E = {(u, v) | u, v are elements of V && the cell(u, v) is not taken}
    

    Now run DFS to find all disconnected trees. Algorithm:

    for each u in V:
        color[u] = white
    
    for each u in V:
        if color[u] == white:
            contains_boundary_edge = False
            DFS-visit( u, contains_boundary_edge )
    
            if not contains_boundary_edge:
                Flood-fill( u )
    
    DFS-visit( u, contains_boundary_edge ):
        color[u] = gray
        for each v in adjacent( u ):
            if color[v] == white:
                if edge(u, v) is a boundary edge: // Can be easily identified if one of u, v is start or end row/col.
                    contains_boundary_edge = True
    
                DFS-visit( v, contains_boundary_edge )
    
        color[u] = black
    
    0 讨论(0)
  • 2021-02-04 08:45

    I think this question can be reduced to a convex hull problem if we consider each # as point x,y then convex hull be give us the x,y of all the # which are absent

    http://en.wikipedia.org/wiki/Convex_hull

    I will try to code it in leisure ..

    0 讨论(0)
  • 2021-02-04 08:50

    You could attack this by processing each '.' node.

    Definition: A '.' node is enclosed if there does not exist a path from the node to the boundary of the map.

    If you agree with the above definition, the algorithm would be to maintain a graph of '.' nodes, where adjacent nodes are connected.

    Every time a node is changed to '#', remove it from this graph, and check each remaining '.' node to see if a path exists from it to one of the nodes on the map border.

    Depending on the size of your map, you made need to attempt various optimizations to limit the number of path searches performed each turn.

    0 讨论(0)
  • 2021-02-04 08:54

    I would start from each neighbor of the picked square, and try to 'escape' to the boundary of the grid. Meanwhile, mark the path followed by 'X'. If you can escape: undo every 'X'. If you cannot escape, replace every 'X' by '#'. I made an example in Java, as shown below.

    int W, H;   
    char[][] input;
    final int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    
    public void handle(int x, int y) {
        // try each neihgbor
        for (int[] d : directions) {
            if (canEscape(input, x, y)) {
                // if we can escape, the path found shouldn't be filled
                // so replace the Xes by '.';
                handleXes(input, false);                
            } else {
                // if we cannot escape, this is a closed shape, so
                // fill with '#'
                handleXes(input, true);
            }
            // note that this can be written more concisely as
            // handleXes(input, !canEscape(input, x, y));
        }
    }    
    
    public boolean canEscape(char[][] grid, int x, int y) {
        if (isEscape(grid, x, y))
            return true
    
        if (isValid(grid, x, y)) {
            // mark as visited
            grid[x][y] = 'X';
            // try each neighbor
            for (int[] d : directions) {
                if (canEscape(grid, x+d[0], y+d[1]))
                    return true;
            }
        }
    
        return false;
    }
    
    public boolean isValid(char[][] grid, int x, int y) {
        return 0 <= x && x < W && 0 <= y && y < H && grid[x][y] == '.';
    }
    
    public boolean isEscape(char[][] grid, int x, int y) {
        return (0 == x || x == W-1 || 0 == y || y == H-1) && grid[x][y] == '.';
    }   
    
    public void handleXes(char[][] grid, boolean fill) {
        for (int x = 0; x < W; x++)
            for (int y = 0; y < H; y++)
                if (grid[x][y] == 'X')
                    grid[x][y] = fill ? '#' : '.';
    }
    
    0 讨论(0)
提交回复
热议问题