——by A Code Rabbit
输入一张迷宫图,全部由 '/'、'\' 组成。
这样,迷宫就变成一个斜线迷宫。
因为输入全为 '/' 、'\' ,因此,这个迷宫将由全部宽度为1的路径组成。
要求输出迷宫中有几个回环,即封闭的路径有几条,其中最长的有多长。
Date Structure :: Graphs
经典的斜线迷宫题。
可用 FloodFill 解决。
首先知道,没有封闭的路径,必然将通往图的外面。
所以只要从图的边界开始 FloodFill,把不满足条件的排除后。
再对每一个点去 FloodFill 即可求出所要的解。
而对于斜线的处理,有三种方法:
1. 九分法:将所有的格子都扩大成 9 * 9 的格子,例如‘/’ 就会变成
然后只要用普通的 FloodFill 对每格上下左右四个方向的 DFS 就可以。
2. 四分法:将所有的格子扩大成 4 * 4 的格子,例如
‘/’ 就会变成然后依然是对每个格子向八个方向 FloodFill ,但是要注意,在 2 * 2 格子中的某点向周围Flood 的时候,只能到达上下左右的 2 * 2格子。
反之如果 FloodFill 后依然在原先的 2 * 2格子,或者对角线方向的 2 * 2 格子的,将会是穿过了 '/' 的非法情况,需要排除掉。
3. 光线反射法:模拟一条光线在迷宫中照射,继续看图:
对于每个格子,光线可能从四个方向射进来。
在 FloodFill 的 时候 ,判断光线来的方向,找到下一个 FloodFill 的格子 即可。三种方法,第一种较为简单,但是要将原图长宽各扩大三倍,得到一张原图九倍大的新图。
而第二种方法,只要将原图扩大四倍,但是要判断要FloodFill的格子是否可以FloodFill。
而第三种方法,较为复杂,对光线进来的四个方向都要判断反射出去的方向,可以用一个 enum 配合 const 数组来映射,好处就是不用扩大原图,时间复杂度相对前两种,常数较低。
// UVaOJ 705 // Slash Maze // by A Code Rabbit #include <cstdio> struct Change { int x; int y; }; Change CHANGE[] = { {-1, 0}, { 0, -1}, { 0, 1}, { 1, 0}, }; const int LIMITS_W = 1000; const int LIMITS_H = 1000; int num_case = 0; char maze[LIMITS_H][LIMITS_W]; int w, h; int w_maze, h_maze; void EnlargeAndSave(int x, int y, char ch); int FloodFill(int x, int y); int main() { while (scanf("%d%d", &w, &h)) { getchar(); // Exit. if (!w && !h) { break; } // Inputs. for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { EnlargeAndSave(i, j, getchar()); } getchar(); } w_maze = w * 3; h_maze = h * 3; // DFS: Remove grids of the maze without cycles. for (int i = 0; i < h_maze; ++i) { FloodFill(i, 0); FloodFill(i, w_maze - 1); } for (int i = 0; i < w_maze; ++i) { FloodFill(0, i); FloodFill(h_maze - 1, i); } // DFS: Search and compete the maze with cycles. int max = 0; int sum = 0; for (int i = 0; i < h_maze; ++i) { for (int j = 0; j < w_maze; ++j) { int result = FloodFill(i, j) / 3; if (result) { max = result > max ? result : max; ++sum; } } } // Outputs. printf("Maze #%d:\n", ++num_case); if (sum) { printf("%d Cycles; the longest has length %d.\n", sum, max); } else { printf("There are no cycles.\n"); } printf("\n"); } return 0; } void EnlargeAndSave(int x, int y, char ch) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { maze[x * 3 + i][y * 3 + j] = ' '; } } if (ch == '/') { maze[x * 3][y * 3 + 2] = '#'; maze[x * 3 + 1][y * 3 + 1] = '#'; maze[x * 3 + 2][y * 3] = '#'; } else { maze[x * 3][y * 3] = '#'; maze[x * 3 + 1][y * 3 + 1] = '#'; maze[x * 3 + 2][y * 3 + 2] = '#'; } } int FloodFill(int x, int y) { // Exit. if (x < 0 || x >= h_maze || y < 0 || y >= w_maze) { return 0; } if (maze[x][y] != ' ') { return 0; } // Continue. maze[x][y] = '#'; int sum = 1; for (int i = 0; i < 4; ++i) { sum += FloodFill(x + CHANGE[i].x, y + CHANGE[i].y); } return sum; }
// UVaOJ 705 // Slash Maze // by A Code Rabbit #include <cstdio> struct Change { int x; int y; }; Change STRAIGHT_CHANGE[] = { {-1, 0}, { 0, -1}, { 0, 1}, { 1, 0}, }; Change SLASH_CHANGE[] = { {-1, -1}, {-1, 1}, { 1, -1}, { 1, 1}, }; const int LIMITS_W = 500; const int LIMITS_H = 500; int num_case = 0; char maze[LIMITS_H][LIMITS_W]; int w, h; int w_maze, h_maze; void EnlargeAndSave(int x, int y, char ch); bool canArrive(int x, int y, Change change); int FloodFill(int x, int y); int main() { while (scanf("%d%d", &w, &h)) { getchar(); // Exit. if (!w && !h) { break; } // Inputs. for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { EnlargeAndSave(i, j, getchar()); } getchar(); } w_maze = w * 2; h_maze = h * 2; // DFS: Remove grids of the maze without cycles. for (int i = 0; i < h_maze; ++i) { FloodFill(i, 0); FloodFill(i, w_maze - 1); } for (int i = 0; i < w_maze; ++i) { FloodFill(0, i); FloodFill(h_maze - 1, i); } // DFS: Search and compete the maze with cycles. int max = 0; int sum = 0; for (int i = 0; i < h_maze; ++i) { for (int j = 0; j < w_maze; ++j) { int result = FloodFill(i, j); if (result) { max = result > max ? result : max; ++sum; } } } // Outputs. printf("Maze #%d:\n", ++num_case); if (sum) { printf("%d Cycles; the longest has length %d.\n", sum, max); } else { printf("There are no cycles.\n"); } printf("\n"); } return 0; } void EnlargeAndSave(int x, int y, char ch) { maze[x * 2][y * 2] = ch == '/' ? ' ' : '#'; maze[x * 2][y * 2 + 1] = ch == '/' ? '#' : ' '; maze[x * 2 + 1][y * 2] = ch == '/' ? '#' : ' '; maze[x * 2 + 1][y * 2 + 1] = ch == '/' ? ' ' : '#'; } bool canArrive(int x, int y, Change change) { int x_after_change = x % 2 + change.x; int y_after_change = y % 2 + change.y; if (0 <= x_after_change && x_after_change < 2 && 0 <= y_after_change && y_after_change < 2) { return false; } else if ((x_after_change < 0 || x_after_change >= 2) && (y_after_change < 0 || y_after_change >= 2)) { return false; } else { return true; } printf("\n"); } int FloodFill(int x, int y) { // Exit. if (x < 0 || x >= h_maze || y < 0 || y >= w_maze) { return 0; } if (maze[x][y] != ' ') { return 0; } // Continue. maze[x][y] = '.'; int sum = 1; for (int i = 0; i < 4; ++i) { sum += FloodFill(x + STRAIGHT_CHANGE[i].x, y + STRAIGHT_CHANGE[i].y); } for (int i = 0; i < 4; ++i) { if (canArrive(x, y, SLASH_CHANGE[i])) { sum += FloodFill(x + SLASH_CHANGE[i].x, y + SLASH_CHANGE[i].y); } } return sum; }
// UVaOJ 705 // Slash Maze // by A Code Rabbit #include <cstdio> #include <cstring> enum Direction { UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3, }; struct Change { int x; int y; }; const Direction DIRECTION[] = { UP, DOWN, LEFT, RIGHT, }; // Form four directions what are UP, DOWN, LEFT, RIGHT. const Change CHANGE[] = { {-1, 0}, { 1, 0}, { 0, -1}, { 0, 1}, }; // Form four directions what are UP, DOWN, LEFT, RIGHT. const Direction REFLEX_SLASH[] = { LEFT, RIGHT, UP, DOWN, }; const Direction REFLEX_BACKSLASH[] = { RIGHT, LEFT, DOWN, UP, }; const int LIMITS_W = 100; const int LIMITS_H = 100; int num_case = 0; char maze[LIMITS_W][LIMITS_H]; int w, h; bool is_visited[LIMITS_W][LIMITS_H][4]; Direction Opposite(Direction direction); int FloodFill(int x, int y, Direction direction); int main() { while (scanf("%d%d", &w, &h)) { getchar(); // Exit. if (!w && !h) { break; } // Inputs. for (int i = 0; i < h; ++i) { gets(maze[i]); } // DFS: Remove grids of the maze without cycles. memset(is_visited, false, sizeof(is_visited)); for (int i = 0; i < h; ++i) { FloodFill(i, 0, LEFT); FloodFill(i, w - 1, RIGHT); } for (int i = 0; i < w; ++i) { FloodFill(0, i, UP); FloodFill(h - 1, i, DOWN); } //Show(); // DFS: Search and compete the maze with cycles. int max = 0; int sum = 0; for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { for (int k = 0; k < 4; k++) { int result = FloodFill(i, j, DIRECTION[k]); if (result) { max = result > max ? result : max; ++sum; } } } } // Outputs. //Show(); printf("Maze #%d:\n", ++num_case); if (sum) { printf("%d Cycles; the longest has length %d.\n", sum, max); } else { printf("There are no cycles.\n"); } printf("\n"); } return 0; } Direction Opposite(Direction direction) { if (direction == LEFT) { return RIGHT; } else if (direction == RIGHT) { return LEFT; } else if (direction == UP) { return DOWN; } else if (direction == DOWN) { return UP; } } int FloodFill(int x, int y, Direction direction) { // Exit. if (x < 0 || x >= h || y < 0 || y >= w) { return 0; } if (is_visited[x][y][direction]) { return 0; } is_visited[x][y][direction] = true; // Continue. Direction direction_leave; if (maze[x][y] == '/') { direction_leave = REFLEX_SLASH[direction]; } else { direction_leave = REFLEX_BACKSLASH[direction]; } is_visited[x][y][direction_leave] = true; return 1 + FloodFill(x + CHANGE[direction_leave].x, y + CHANGE[direction_leave].y, Opposite(direction_leave)); }
下载PDF
参考资料:wjjayo博客 crystal_yi博客 Penseur博客