迷宫图 用 FloodFill 解决

来源:互联网 发布:netflix推荐算法竞赛 编辑:程序博客网 时间:2024/06/05 16:46

思路:

  1. int FloodFill(int x, int y) {  
  2.     // 首先判断是否出界
  3.     if (x < 0 || x >= h_maze  
  4.      || y < 0 || y >= w_maze) {  
  5.         return 0;  
  6.     }  
  7.      //再判断已经扫描过,如果扫描过就退出
  8.     if (maze[x][y] != ' ') {  
  9.         return 0;  
  10.     }  
  11.     // 最后进行下一步的扫描即下一个方格,下个方格的四个方向都要扫描一篇(像泛洪).  
  12.     maze[x][y] = '#';  
  13.     int sum = 1;  
  14.     for (int i = 0; i < 4; ++i) {  
  15.         sum += FloodFill(x + CHANGE[i].x, y + CHANGE[i].y);  
  16.     }  
  17.     return sum;  
  18. }  

Description

输入一张迷宫图,全部由 '/'、'\' 组成。
这样,迷宫就变成一个斜线迷宫。


因为输入全为 '/' 、'\' ,因此,这个迷宫将由全部宽度为1的路径组成。
要求输出迷宫中有几个回环,即封闭的路径有几条,其中最长的有多长。


Types

Date Structure :: Graphs


Analysis

经典的斜线迷宫题。

可用 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 数组来映射,好处就是不用扩大原图,时间复杂度相对前两种,常数较低。


Solution

1. 九分法
[cpp] view plaincopy
  1. // UVaOJ 705  
  2. // Slash Maze  
  3. // by A Code Rabbit  
  4.   
  5. #include <cstdio>  
  6.   
  7. struct Change {  
  8.     int x;  
  9.     int y;  
  10. };  
  11.   
  12. Change CHANGE[] = {  
  13.               {-1, 0},  
  14.     { 0, -1},          { 0, 1},  
  15.               { 1, 0},  
  16. };  
  17.   
  18. const int LIMITS_W = 1000;  
  19. const int LIMITS_H = 1000;  
  20.   
  21. int num_case = 0;  
  22.   
  23. char maze[LIMITS_H][LIMITS_W];  
  24. int w, h;  
  25. int w_maze, h_maze;  
  26.   
  27. void EnlargeAndSave(int x, int y, char ch);  
  28.   
  29. int FloodFill(int x, int y);  
  30.   
  31. int main() {  
  32.     while (scanf("%d%d", &w, &h)) {  
  33.         getchar();  
  34.         // Exit.  
  35.         if (!w && !h) {  
  36.             break;  
  37.         }  
  38.         // Inputs.  
  39.         for (int i = 0; i < h; ++i) {  
  40.             for (int j = 0; j < w; ++j) {  
  41.                 EnlargeAndSave(i, j, getchar());  
  42.             }  
  43.             getchar();  
  44.         }  
  45.         w_maze = w * 3;  
  46.         h_maze = h * 3;  
  47.         // DFS: Remove grids of the maze without cycles.  
  48.         for (int i = 0; i < h_maze; ++i) {  
  49.             FloodFill(i, 0);  
  50.             FloodFill(i, w_maze - 1);  
  51.         }  
  52.         for (int i = 0; i < w_maze; ++i) {  
  53.             FloodFill(0, i);  
  54.             FloodFill(h_maze - 1, i);  
  55.         }  
  56.         // DFS: Search and compete the maze with cycles.  
  57.         int max = 0;  
  58.         int sum = 0;  
  59.         for (int i = 0; i < h_maze; ++i) {  
  60.             for (int j = 0; j < w_maze; ++j) {  
  61.                 int result = FloodFill(i, j) / 3;  
  62.                 if (result) {  
  63.                     max = result > max ? result : max;  
  64.                     ++sum;  
  65.                 }  
  66.             }  
  67.         }  
  68.         // Outputs.  
  69.         printf("Maze #%d:\n", ++num_case);  
  70.         if (sum) {  
  71.             printf("%d Cycles; the longest has length %d.\n", sum, max);  
  72.         } else {  
  73.             printf("There are no cycles.\n");  
  74.         }  
  75.         printf("\n");  
  76.     }  
  77.       
  78.     return 0;  
  79. }  
  80.   
  81. void EnlargeAndSave(int x, int y, char ch) {  
  82.     for (int i = 0; i < 3; ++i) {  
  83.         for (int j = 0; j < 3; ++j) {  
  84.             maze[x * 3 + i][y * 3 + j] = ' ';  
  85.         }  
  86.     }  
  87.     if (ch == '/') {  
  88.         maze[x * 3][y * 3 + 2] = '#';  
  89.         maze[x * 3 + 1][y * 3 + 1] = '#';  
  90.         maze[x * 3 + 2][y * 3] = '#';  
  91.     } else {  
  92.         maze[x * 3][y * 3] = '#';  
  93.         maze[x * 3 + 1][y * 3 + 1] = '#';  
  94.         maze[x * 3 + 2][y * 3 + 2] = '#';  
  95.     }  
  96. }  
  97.   
  98. int FloodFill(int x, int y) {  
  99.     // Exit.  
  100.     if (x < 0 || x >= h_maze  
  101.      || y < 0 || y >= w_maze) {  
  102.         return 0;  
  103.     }  
  104.     if (maze[x][y] != ' ') {  
  105.         return 0;  
  106.     }  
  107.     // Continue.  
  108.     maze[x][y] = '#';  
  109.     int sum = 1;  
  110.     for (int i = 0; i < 4; ++i) {  
  111.         sum += FloodFill(x + CHANGE[i].x, y + CHANGE[i].y);  
  112.     }  
  113.     return sum;  
  114. }  

2. 四分法
[cpp] view plaincopy
  1. // UVaOJ 705  
  2. // Slash Maze  
  3. // by A Code Rabbit  
  4.   
  5. #include <cstdio>  
  6.   
  7. struct Change {  
  8.     int x;  
  9.     int y;  
  10. };  
  11.   
  12. Change STRAIGHT_CHANGE[] = {  
  13.               {-1, 0},  
  14.     { 0, -1},          { 0, 1},  
  15.               { 1, 0},  
  16. };  
  17.   
  18. Change SLASH_CHANGE[] = {  
  19.     {-1, -1},          {-1, 1},  
  20.       
  21.     { 1, -1},          { 1, 1},  
  22. };  
  23.   
  24. const int LIMITS_W = 500;  
  25. const int LIMITS_H = 500;  
  26.   
  27. int num_case = 0;  
  28.   
  29. char maze[LIMITS_H][LIMITS_W];  
  30. int w, h;  
  31. int w_maze, h_maze;  
  32.   
  33. void EnlargeAndSave(int x, int y, char ch);  
  34.   
  35. bool canArrive(int x, int y, Change change);  
  36. int FloodFill(int x, int y);  
  37.   
  38. int main() {  
  39.     while (scanf("%d%d", &w, &h)) {  
  40.         getchar();  
  41.         // Exit.  
  42.         if (!w && !h) {  
  43.             break;  
  44.         }  
  45.         // Inputs.  
  46.         for (int i = 0; i < h; ++i) {  
  47.             for (int j = 0; j < w; ++j) {  
  48.                 EnlargeAndSave(i, j, getchar());  
  49.             }  
  50.             getchar();  
  51.         }  
  52.         w_maze = w * 2;  
  53.         h_maze = h * 2;  
  54.         // DFS: Remove grids of the maze without cycles.  
  55.         for (int i = 0; i < h_maze; ++i) {  
  56.             FloodFill(i, 0);  
  57.             FloodFill(i, w_maze - 1);  
  58.         }  
  59.         for (int i = 0; i < w_maze; ++i) {  
  60.             FloodFill(0, i);  
  61.             FloodFill(h_maze - 1, i);  
  62.         }  
  63.         // DFS: Search and compete the maze with cycles.  
  64.         int max = 0;  
  65.         int sum = 0;  
  66.         for (int i = 0; i < h_maze; ++i) {  
  67.             for (int j = 0; j < w_maze; ++j) {  
  68.                 int result = FloodFill(i, j);  
  69.                 if (result) {  
  70.                     max = result > max ? result : max;  
  71.                     ++sum;  
  72.                 }  
  73.             }  
  74.         }  
  75.         // Outputs.  
  76.         printf("Maze #%d:\n", ++num_case);  
  77.         if (sum) {  
  78.             printf("%d Cycles; the longest has length %d.\n", sum, max);  
  79.         } else {  
  80.             printf("There are no cycles.\n");  
  81.         }  
  82.         printf("\n");  
  83.     }  
  84.       
  85.     return 0;  
  86. }  
  87.   
  88. void EnlargeAndSave(int x, int y, char ch) {  
  89.     maze[x * 2][y * 2] = ch == '/' ? ' ' : '#';  
  90.     maze[x * 2][y * 2 + 1] = ch == '/' ? '#' : ' ';  
  91.     maze[x * 2 + 1][y * 2] = ch == '/' ? '#' : ' ';  
  92.     maze[x * 2 + 1][y * 2 + 1] = ch == '/' ? ' ' : '#';  
  93. }  
  94.   
  95. bool canArrive(int x, int y, Change change) {  
  96.     int x_after_change = x % 2 + change.x;  
  97.     int y_after_change = y % 2 + change.y;  
  98.     if (0 <= x_after_change && x_after_change < 2  
  99.      && 0 <= y_after_change && y_after_change < 2) {  
  100.         return false;  
  101.     } else  
  102.     if ((x_after_change < 0 || x_after_change >= 2)  
  103.      && (y_after_change < 0 || y_after_change >= 2)) {  
  104.         return false;  
  105.     } else {  
  106.         return true;  
  107.     }  
  108.     printf("\n");  
  109. }  
  110.   
  111. int FloodFill(int x, int y) {  
  112.     // Exit.  
  113.     if (x < 0 || x >= h_maze  
  114.      || y < 0 || y >= w_maze) {  
  115.         return 0;  
  116.     }  
  117.     if (maze[x][y] != ' ') {  
  118.         return 0;  
  119.     }  
  120.     // Continue.  
  121.     maze[x][y] = '.';  
  122.     int sum = 1;  
  123.     for (int i = 0; i < 4; ++i) {  
  124.         sum += FloodFill(x + STRAIGHT_CHANGE[i].x, y + STRAIGHT_CHANGE[i].y);  
  125.     }  
  126.     for (int i = 0; i < 4; ++i) {  
  127.         if (canArrive(x, y, SLASH_CHANGE[i])) {  
  128.             sum += FloodFill(x + SLASH_CHANGE[i].x, y + SLASH_CHANGE[i].y);  
  129.         }  
  130.     }  
  131.   
  132.     return sum;  
  133. }  

3. 光线反射法
[cpp] view plaincopy
  1. // UVaOJ 705  
  2. // Slash Maze  
  3. // by A Code Rabbit  
  4.   
  5. #include <cstdio>  
  6. #include <cstring>  
  7.   
  8.   
  9. enum Direction {  
  10.     UP = 0,  
  11.     DOWN = 1,  
  12.     LEFT = 2,  
  13.     RIGHT = 3,  
  14. };  
  15.   
  16. struct Change {  
  17.     int x;  
  18.     int y;  
  19. };  
  20.   
  21. const Direction DIRECTION[] = {  
  22.     UP,  
  23.     DOWN,  
  24.     LEFT,  
  25.     RIGHT,  
  26. };  
  27. // Form four directions what are UP, DOWN, LEFT, RIGHT.  
  28. const Change CHANGE[] = {  
  29.     {-1,  0},  
  30.     { 1,  0},  
  31.     { 0, -1},  
  32.     { 0,  1},  
  33. };  
  34.   
  35. // Form four directions what are UP, DOWN, LEFT, RIGHT.  
  36. const Direction REFLEX_SLASH[] = {  
  37.     LEFT,  
  38.     RIGHT,  
  39.     UP,  
  40.     DOWN,  
  41. };  
  42. const Direction REFLEX_BACKSLASH[] = {  
  43.     RIGHT,  
  44.     LEFT,  
  45.     DOWN,  
  46.     UP,   
  47. };  
  48.   
  49. const int LIMITS_W = 100;  
  50. const int LIMITS_H = 100;  
  51.   
  52. int num_case = 0;  
  53.   
  54. char maze[LIMITS_W][LIMITS_H];  
  55. int w, h;  
  56.   
  57. bool is_visited[LIMITS_W][LIMITS_H][4];  
  58.   
  59. Direction Opposite(Direction direction);  
  60. int FloodFill(int x, int y, Direction direction);  
  61.   
  62. int main() {  
  63.     while (scanf("%d%d", &w, &h)) {  
  64.         getchar();  
  65.         // Exit.  
  66.         if (!w && !h) {  
  67.             break;  
  68.         }  
  69.         // Inputs.  
  70.         for (int i = 0; i < h; ++i) {  
  71.             gets(maze[i]);  
  72.         }  
  73.         // DFS: Remove grids of the maze without cycles.  
  74.         memset(is_visited, falsesizeof(is_visited));  
  75.         for (int i = 0; i < h; ++i) {  
  76.             FloodFill(i, 0, LEFT);  
  77.             FloodFill(i, w - 1, RIGHT);  
  78.         }  
  79.         for (int i = 0; i < w; ++i) {  
  80.             FloodFill(0, i, UP);  
  81.             FloodFill(h - 1, i, DOWN);  
  82.         }  
  83.         //Show();  
  84.         // DFS: Search and compete the maze with cycles.  
  85.         int max = 0;  
  86.         int sum = 0;  
  87.         for (int i = 0; i < h; ++i) {  
  88.             for (int j = 0; j < w; ++j) {  
  89.                 for (int k = 0; k < 4; k++) {  
  90.                     int result = FloodFill(i, j, DIRECTION[k]);  
  91.                     if (result) {  
  92.                         max = result > max ? result : max;  
  93.                         ++sum;  
  94.                     }  
  95.                 }  
  96.             }  
  97.         }  
  98.         // Outputs.  
  99.         //Show();  
  100.         printf("Maze #%d:\n", ++num_case);  
  101.         if (sum) {  
  102.             printf("%d Cycles; the longest has length %d.\n", sum, max);  
  103.         } else {  
  104.             printf("There are no cycles.\n");  
  105.         }  
  106.         printf("\n");  
  107.     }  
  108.   
  109.   
  110.     return 0;  
  111. }  
  112.   
  113. Direction Opposite(Direction direction) {  
  114.     if (direction == LEFT) {  
  115.         return RIGHT;  
  116.     } else  
  117.     if (direction == RIGHT) {  
  118.         return LEFT;  
  119.     } else  
  120.     if (direction == UP) {  
  121.         return DOWN;  
  122.     } else  
  123.     if (direction == DOWN) {  
  124.         return UP;  
  125.     }  
  126. }  
  127.   
  128. int FloodFill(int x, int y, Direction direction) {  
  129.     // Exit.  
  130.     if (x < 0 || x >= h  
  131.      || y < 0 || y >= w) {  
  132.         return 0;  
  133.     }  
  134.     if (is_visited[x][y][direction]) {  
  135.         return 0;  
  136.     }  
  137.     is_visited[x][y][direction] = true;  
  138.     // Continue.  
  139.     Direction direction_leave;  
  140.     if (maze[x][y] == '/') {  
  141.         direction_leave = REFLEX_SLASH[direction];  
  142.     } else {  
  143.         direction_leave = REFLEX_BACKSLASH[direction];   
  144.     }  
  145.     is_visited[x][y][direction_leave] = true;  
  146.     return 1 + FloodFill(x + CHANGE[direction_leave].x,  
  147.                          y + CHANGE[direction_leave].y,  
  148.                          Opposite(direction_leave));  
  149. }  
0 0
原创粉丝点击