迷宫问题
来源:互联网 发布:血液问题人数调查数据 编辑:程序博客网 时间:2024/06/04 01:02
迷宫最优解问题:
迷宫地形我们可以通过读文件的形式,通过已知入口逐个遍历坐标寻找通路。
文件如图:
每个坐标的位置用结构体来记录:
- struct Pos //位置坐标
- {
- int _row;
- int _col;
- };
定义行列范围
- #define M 10 //行
- #define N 10 //列
初始化迷宫数组:
将通过读文件的方式获取的字符转成整型数据,保存在M行N列的数组中。
- void InitMaze(int* maze)
- {
- struct WavHeadhWAV;
- FILE* fout = fopen("MazeMap.txt", "r"); // .txt文件要放在当前目录下
- if (fout == NULL) // 这里一定要检查读文件是否成功
- {
- cout << "can't find MazeMap.txt !" << endl<<endl;
- return;
- }
- for (int i = 0; i < M; i++)
- {
- for (int j = 0; j < N;)
- {
- char ch = fgetc(fout);
- if (ch=='1'||ch=='0')
- {
- maze[i*N + j] = ch - '0';
- j++;
- }
- }
- }
- fclose(fout);
- }
回溯查找通路:
利用栈来存储通路,通过上下左右四个方向依次遍历,如果该位置满足条件,就将它入栈,并将该位置的数据置为2;如果四个方向都不满足条件就执行出栈操作,回溯查找满足条件的位置(这时候如果栈为空了,说明查找通路失败),继续循环遍历,直到找到出口为止。
这里建立一个最小栈,如果找到出路,就将该栈赋给最小栈,并将出口置为1,继续回溯查找通路,如果又一次找到通路,就将该栈的长度与最小栈进行比较,如果该栈长度比最小栈还要小,就将它再一次赋给最小栈(保证最小栈是最短的通路),继续回溯,直到整个栈为空,回到了入口,程序结束。
- bool SearchMazePath(int *maze, Pos entry, stack<Pos>& paths) // 利用栈回溯查找通路,并实现迷宫的最优解
- {
- assert(maze);
- stack<Pos>min;
- paths.push(entry);
- while (!paths.empty())
- {
- Pos cur = paths.top();
- maze[cur._row*N+cur._col] = 2;
- if (cur._row==M-1)
- {
- if (paths.size()< min.size() || min.size() == 0)
- {
- min = paths;
- }
- paths.pop();
- maze[min.top()._row*N + min.top()._col] = 1;
- }
- Pos next = cur;
- next._col--; //左
- if (CheckIsAccess(maze, next))
- {
- paths.push(next);
- maze[next._row*N + next._col] = 2;
- continue;
- }
- next = cur;
- next._col++; //右
- if (CheckIsAccess(maze, next))
- {
- paths.push(next);
- maze[next._row*N + next._col] = 2;
- continue;
- }
- next = cur;
- next._row--; //上
- if (CheckIsAccess(maze, next))
- {
- paths.push(next);
- maze[next._row*N + next._col] = 2;
- continue;
- }
- next = cur;
- next._row++; //下
- if (CheckIsAccess(maze, next))
- {
- paths.push(next);
- maze[next._row*N + next._col] = 2;
- continue;
- }
- paths.pop();
- }
- if (paths.empty()&&!min.empty())
- {
- maze[min.top()._row*N + min.top()._col] = 2;
- return true;
- }
- return false;
- }
检查该位置是否合法:(坐标在行列范围之内)
- bool CheckIsAccess(int* maze, const Pos& next) // 检查该位置是否合法
- {
- assert(maze);
- if ((next._row >= 0 && next._row <= N) && (next._col >= 0 && next._col < M) && maze[next._row*N + next._col] == 0)
- {
- return true;
- }
- return false;
- }
打印迷宫:
- void PrintMaze(int *maze) // 打印迷宫
- {
- assert(maze);
- for (int i = 0; i < M; i++)
- {
- for (int j = 0; j < N; j++)
- {
- cout << maze[i*N + j] <<" " ;
- }
- cout << endl;
- }
- cout << endl;
- }
下面简单阐述下使用栈(循环)和使用递归来走迷宫的区别:
使用递归:
分为两个部分:
一部分为已走过的路径(通路)
另一问题是:递归的子问题(根据下一个可以通的位置继续查找出口)。
将走过的路径保存在栈帧内。
递归结束时返回上一层栈帧,销毁当前栈帧。使用栈(保存走过的路径)
分为两个部分:
一部分为已走过的路径(通路),将其保存在栈内
另一部分为:
试探四个方向,沿着某个可以走通的方向一直试探下去,直到走不通时,退出栈顶元素,栈顶元素始终为当前所处的位置。
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;#include<cassert>struct Pos//设置坐标{ Pos(int x, int y) :_x(x) , _y(y) {} int _x; int _y;};template<size_t M,size_t N>class Maze{public: Maze(int **arr, FILE* fp)//构造迷宫 :_row(M) , _col(N) , _maze(arr) { int ch = 0; assert(fp); for (size_t i = 0; i < _row; ++i)//从文件中读取迷宫 { for (size_t j = 0; j < _col;) { char ch = fgetc(fp); if (ch == '0' || ch == '1') { _maze[i][j] = ch - '0'; ++j; } } } fclose(fp); } bool PassMaze(Pos Entry) { //递归算法 Pos cur = Entry; Pos next = cur; _maze[next._x][next._y] = 2;//将走过的路进行标记 //判断是否为出口 if (next._x == N - 1) { return true; } //向上查探 next._x -= 1; if (_CheckAccess(next)) { if (PassMaze(next)) { return true; } } //向右查探 next = cur; next._y += 1; if (_CheckAccess(next)) { if (PassMaze(next)) { return true; } } //向下查探 next = cur; next._x += 1; if (_CheckAccess(next)) { if (PassMaze(next)) { return true; } } //向左查探 next = cur; next._y -= 1; if (_CheckAccess(next)) { if (PassMaze(next)) { return true; } } //走到死胡同时标记为3 _maze[cur._x][cur._y] = 3; return false; } ~Maze() { for (int i = 0; i <_row; ++i) { delete[] _maze[i]; } delete[] _maze; } friend ostream& operator<<(ostream& out, Maze& m);protected: bool _CheckAccess(Pos cur) { if (cur._x >= 0 && cur._x < N && cur._y >= 0 && cur._y < N && _maze[cur._x][cur._y] == 1) { return true; } return false; }private: int** _maze; int _row; int _col;}; ostream& operator<<(ostream& out, Maze<10,10>& m){ for (int i = 0; i < m._row; ++i) { for (int j = 0; j < m._col; ++j) { out << m._maze[i][j] << " "; } cout << endl; } return out;}测试代码:
void Test(){ FILE* fp = fopen("Maze.txt", "r"); int row = 0; int col = 0; fscanf(fp, "%d %d", &row, &col); int Start_x = 0; int Start_y = 0; fscanf(fp, "%d %d", &Start_x, &Start_y); //动态开辟二维数组 int **arr = new int*[row]; for (int i = 0; i < col; ++i) { arr[i] = new int[col]; } Maze<10,10> maze(arr,fp);//初始化迷宫 cout << maze << endl; cout << maze.PassMaze(Pos(Start_x, Start_y)) << endl; cout << maze << endl; fclose(fp);}int main(){ Test(); return 0;}2.非递归走迷宫(利用栈来保存迷宫的路径)
#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;#include<cassert>#include<stack>struct Pos//设置坐标{ Pos(int x, int y) :_x(x) , _y(y) {} int _x; int _y;};template<size_t M,size_t N>class Maze{public: Maze(int **arr, FILE* fp)//构造迷宫 :_row(M) , _col(N) , _maze(arr) { int ch = 0; assert(fp); for (size_t i = 0; i < _row; ++i)//从文件中读取迷宫 { for (size_t j = 0; j < _col;) { char ch = fgetc(fp); if (ch == '0' || ch == '1') { _maze[i][j] = ch - '0'; ++j; } } } fclose(fp); } //使用循环 bool PassMaze(Pos Entry) { stack<Pos > s; s.push(Entry); _maze[Entry._x][Entry._y] = 2; while (!s.empty()) { Pos cur = s.top(); _maze[cur._x][cur._y] = 2; if (cur._x == N - 1) { return true; } //向上查探 Pos next = cur; next._x -= 1; if (_CheckAccess(next)) { s.push(next); continue; } //向右查探 next = cur; next._y += 1; if (_CheckAccess(next)) { s.push(next); continue; } //向下查探 next = cur; next._x += 1; if (_CheckAccess(next)) { s.push(next); continue; } //向左查探 next = cur; next._y -= 1; if (_CheckAccess(next)) { s.push(next); continue; } s.pop(); _maze[cur._x][cur._y] = 3; } return false; } ~Maze() { for (int i = 0; i <_row; ++i) { delete[] _maze[i]; } delete[] _maze; } friend ostream& operator<<(ostream& out, Maze& m);protected: bool _CheckAccess(Pos cur) { if (cur._x >= 0 && cur._x < N && cur._y >= 0 && cur._y < N && _maze[cur._x][cur._y] == 1) { return true; } return false; }private: int** _maze; int _row; int _col;}; ostream& operator<<(ostream& out, Maze<10,10>& m){ for (int i = 0; i < m._row; ++i) { for (int j = 0; j < m._col; ++j) { out << m._maze[i][j] << " "; } cout << endl; } return out;}测试代码如下:
void Test(){ FILE* fp = fopen("Maze.txt", "r"); int row = 0; int col = 0; fscanf(fp, "%d %d", &row, &col); int Start_x = 0; int Start_y = 0; fscanf(fp, "%d %d", &Start_x, &Start_y); //动态开辟二维数组 int **arr = new int*[row]; for (int i = 0; i < col; ++i) { arr[i] = new int[col]; } Maze<10,10> maze(arr,fp);//初始化迷宫 cout << maze << endl; cout << maze.PassMaze(Pos(Start_x, Start_y)) << endl; cout << maze << endl; fclose(fp);}int main(){ Test(); return 0;}
阅读全文
0 0
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题...
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 1136. A Delayed Palindrome (20)
- redis学习--下载、安装
- Tomcat中 HttpServletRequst的获取网页的几种方法比较
- 简单说一说Java的内存泄漏
- LINQ、反射和特性
- 迷宫问题
- 选择排序和插入排序
- machine learning实践学习二:K-Nearest Neighbors
- 场次降雨数据划分
- 一只程序猿的养成日记 第一章 第十五节 递归和非递归分别实现求n的阶乘
- 吉大路由器使用教程
- JavaWeb学习笔记-servlet-01-概述
- Android AndFix热更新
- The advance of Java -- IO, Thread(Day05)