我们来看看这张地图,其中'#'表示一个正方形和'。'说明了一个免费的广场:
1 . # # # . . 2 . # . . # . 3 # . . . . # 4 . # # # . . 5 . . . . . . 6 . . . . . . - 1 2 3 4 5 6
现在,如果我在正方形4,5中放置一个'#',那么这个区域就会被“填充”:
1 . # # # . . 2 . # # # # . 3 # # # # # # 4 . # # # # . 5 . . . . . . 6 . . . . . . - 1 2 3 4 5 6
那么,找到“有限广场”的最佳方法是什么,我可以在哪里开始填充或填充有限区域的其他填充算法?
答案 0 :(得分:6)
如果您可以将问题转换为图表,那么您要查找的是识别连接的组件。如果连接的组件不包含作为边界边的边,那么您已找到需要填充的区域。
如果我这样定义图形:
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}
现在运行DFS
以查找所有已断开连接的树。算法:
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
答案 1 :(得分:3)
我认为如果我们将每个#视为点x,那么这个问题可以简化为凸包问题,然后凸包给我们所有#不存在的x,y
http://en.wikipedia.org/wiki/Convex_hull
我会尝试在休闲时编码..
答案 2 :(得分:2)
你可以通过处理每个'。'来攻击它。节点
定义:A'。'如果不存在从节点到地图边界的路径,则封闭节点。
如果您同意上述定义,则算法将维护图表'。'节点,相邻节点连接在一起。
每次将某个节点更改为“#”时,请将其从此图表中删除,然后检查每个剩余的“。”节点,以查看是否存在从其到地图边界上的某个节点的路径。
根据地图的大小,您需要尝试各种优化来限制每回合执行的路径搜索次数。
答案 3 :(得分:1)
如果您将此地图建模为图表,并且每个方块都连接到其四个邻居,则可以使用bridge finding algorithm找到所需的方块。
请注意,此模型有时会为您提供几个子图,因此它可能会在边界周围产生许多误报,因为添加#
肯定会将某些节点与其余节点分开。要解决这个问题,您可以在图表周围填充两个级别的方块,这样就不会有单个#
将边界节点与其他节点分开。
@ svick的评论启发了这种方法。
答案 4 :(得分:1)
我会从拾取的方块的每个邻居开始,并尝试“逃离”到网格的边界。同时,标记路径后跟'X'。如果你可以逃脱:撤消每个'X'。如果无法逃脱,请将每个'X'替换为'#'。我在Java中做了一个例子,如下所示。
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 ? '#' : '.';
}