经典迷宫问题

全文转自:http://blog.csdn.net/that163/article/details/8069780       http://blog.csdn.net/that163/article/details/8069764

给定一个迷宫,入口为左上角,出口为右下角,问是否有路径从入口到出口,若有则输出一条这样的路径。注意移动可以从上、下、左、右、上左、上右、下左、下右八个方向进行。迷宫输入0表示可走,输入1表示墙。易得可以用1将迷宫围起来避免边界问题。

本题采用DFS算法给出解。

[cpp]  view plain copy
  1. /* 
  2. 迷宫问题(八方向) 
  3. input: 
  4. 1 
  5. 6 8 
  6. 0 1 1 1 0 1 1 1 
  7. 1 0 1 0 1 0 1 0 
  8. 0 1 0 0 1 1 1 1 
  9. 0 1 1 1 0 0 1 1 
  10. 1 0 0 1 1 0 0 0 
  11. 0 1 1 0 0 1 1 0 
  12. output: 
  13. YES 
  14. (1,1) (2,2) (3,1) (4,1) (5,2) (5,3) (6,4) (6,5) (5,6) (4,5) (4,6) (5,7) (5,8) (6,8) (递归) 
  15. (1,1) (2,2) (3,3) (3,4) (4,5) (5,6) (5,7) (6,8) (栈) 
  16. */  
  17. #include<iostream>  
  18. #include<stack>  
  19. using namespace std;  
  20. struct point{  
  21.     int x;  
  22.     int y;  
  23. };  
  24. int **Maze;  
  25. stack<point> sp;  
  26. point move[8]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};  
  27. void Create(int row,int column){  
  28.     //创建迷宫,注意到用0表示可走,1表示墙,将整个输入的迷宫再用墙围着,处理的时候就不用特别注意边界问题  
  29.     int i,j;  
  30.     for(i=0; i<row+2; i++)  
  31.         Maze[i][0] = Maze[i][column+1] = 1;  
  32.     for(j=0; j<column+2; j++)  
  33.         Maze[0][j] = Maze[row+1][j] = 1;  
  34.     for(i=1; i<=row; i++){  
  35.         for(j=1; j<=column; j++){  
  36.             cin>>Maze[i][j];  
  37.         }  
  38.     }  
  39. }  
  40. /* 
  41. bool MazePath(int row,int column,int x,int y){ 
  42.     //判断是否有路径从入口到出口,保存该路径(递归) 
  43.     Maze[x][y] = -1; 
  44.     point temp; 
  45.     temp.x = x; 
  46.     temp.y = y; 
  47.     sp.push(temp); 
  48.     for(int i=0; i<8; i++){ 
  49.         if(x + move[i].x == row && y + move[i].y == column)return true; 
  50.         if(Maze[x + move[i].x][y + move[i].y] == 0){ 
  51.             if(MazePath(row,column,x + move[i].x,y + move[i].y))return true; 
  52.         } 
  53.     } 
  54.     sp.pop(); 
  55.     return false; 
  56. } 
  57. */  
  58. bool MazePath(int row,int column,int x,int y){  
  59.     //判断是否有路径从入口到出口,保存该路径(栈)  
  60.     stack<point> save;  
  61.     bool flag;  
  62.     point now;  
  63.     now.x = x;  
  64.     now.y = y;  
  65.     save.push(now);  
  66.     while(!save.empty()){  
  67.         now = save.top();  
  68.         if(Maze[now.x][now.y] == 0){  
  69.             sp.push(now);  
  70.             Maze[now.x][now.y] = -1;  
  71.         }  
  72.         flag = true;  
  73.         for(int i=0; i<8; i++){  
  74.             if(now.x + move[i].x == row && now.y + move[i].y == column)return true;  
  75.             if(Maze[now.x + move[i].x][now.y + move[i].y] == 0){  
  76.                 point temp;  
  77.                 temp.x = now.x + move[i].x;  
  78.                 temp.y = now.y + move[i].y;  
  79.                 save.push(temp);  
  80.                 flag = false;  
  81.             }  
  82.         }  
  83.         if(flag){  
  84.             save.pop();  
  85.             sp.pop();  
  86.         }  
  87.     }  
  88. }  
  89. void PrintPath(int row,int column){  
  90.     //输出从入口到出口的路径  
  91.     point temp;  
  92.     temp.x = row;  
  93.     temp.y =column;  
  94.     stack<point> pp;  
  95.     pp.push(temp);  
  96.     while(!sp.empty()){  
  97.         temp = sp.top();  
  98.         sp.pop();  
  99.         pp.push(temp);  
  100.     }  
  101.     while(!pp.empty()){  
  102.         temp = pp.top();  
  103.         cout<<'('<<temp.x<<','<<temp.y<<')'<<' ';  
  104.         pp.pop();  
  105.     }  
  106.     cout<<endl;  
  107. }  
  108. int main(){  
  109.     int t,row,column;  
  110.     cin>>t;  
  111.     while(t--){  
  112.         cin>>row>>column;  
  113.         Maze = new int*[row + 2];  
  114.         for(int i=0; i<row+2; i++)Maze[i] = new int[column + 2];  
  115.         Create(row,column);  
  116.         if(MazePath(row,column,1,1)){  
  117.             cout<<"YES"<<endl;  
  118.             PrintPath(row,column);  
  119.         }  
  120.         else cout<<"NO"<<endl;  
  121.     }  
  122.     return 0;  
  123. }  
自己测试联系代码:

#include <iostream>
#include <string>
#include <vector>
#include <stack>

using namespace std;

struct point
{
	int row;
	int col;
};
int **maze;	//迷宫矩阵
stack<point> path;

int direction[8][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
void CreateMaze(int row, int col)
{
	for (int i = 0; i < row + 2; ++i)
		maze[i][0] = maze[i][col + 1] = 1;
	for (int i = 0; i < col + 2; ++i)
		maze[0][i] = maze[row + 1][i] = 1;
	for (int i = 1; i < row + 1; ++i)
	{
		for (int j = 1; j < col + 1; ++j)
		{
			cin >> maze[i][j];
		}
	}
}

//没有用到递归,而是用栈实现了DFS
bool FindMazePath(int row, int col, int n, int m)
{
	if (n == row && m == col)
		return true;
	stack<point> cur;	//保存当前深度的所有满足的点
	point now;
	bool flag;	//当前栈的顶点是否需要删除
	now.row = n, now.col = m;
	cur.push(now);
	while (! cur.empty())	
	{
		now = cur.top();
		if (maze[now.row][now.col] == 0)
		{
			path.push(now);
			maze[now.row][now.col] = -1;
		}

		flag = true;

		for (int i = 0; i < 8; ++i)
		{
			int n_n = now.row + direction[i][0];
			int n_m = now.col + direction[i][1];
			if (n_n == row && n_m == col)
				return true;
			if (maze[n_n][n_m] == 0)
			{
				point tmp;
				tmp.row = n_n, tmp.col = n_m;
				cur.push(tmp);	//cur包含每一层的所有满足条件的点;DFS,故path里面只保存了一条路径
				flag = false;
			}
		}
		if (flag)
		{
			cur.pop();
			path.pop();
		}
	}
}

void PrintPath(int row,int column)
{  
	//输出从入口到出口的路径  
	point temp;  
	temp.row = row;  
	temp.col =column;  
	stack<point> pp;  
	pp.push(temp);  
	while(!path.empty())
	{  
		temp = path.top();  
		path.pop();  
		pp.push(temp);  
	}  
	while(!pp.empty())
	{  
		temp = pp.top();  
		cout<<'('<<temp.row<<','<<temp.col<<')'<<' ';  
		pp.pop();  
	}  
	cout<<endl;  
}  

int main()
{
	int row, col;
	cin >> row >> col;
	
	maze = new int*[row + 2];
	for (int i = 0; i < row + 2; ++i)
		maze[i] = new int[col + 2];
	CreateMaze(row, col);
	if (FindMazePath(row, col, 1, 1))
	{
		cout << "Yes" << endl;
		PrintPath(row,col);  
	}  
	else cout<<"No"<<endl;
	//system("pause");
	return 0;
}




采用BFS算法给出解。注意,利用BFS算法给出的路径必然是一条最短路径

[cpp]  view plain copy
  1. /* 
  2. 迷宫问题(八方向) 
  3. input: 
  4. 1 
  5. 6 8 
  6. 0 1 1 1 0 1 1 1 
  7. 1 0 1 0 1 0 1 0 
  8. 0 1 0 0 1 1 1 1 
  9. 0 1 1 1 0 0 1 1 
  10. 1 0 0 1 1 0 0 0 
  11. 0 1 1 0 0 1 1 0 
  12. output: 
  13. YES 
  14. (1,1) (2,2) (3,3) (3,4) (4,5) (4,6) (5,7) (6,8) 
  15. */  
  16. #include<iostream>  
  17. #include<queue>  
  18. #include<stack>  
  19. using namespace std;  
  20. struct point{  
  21.     //横坐标纵坐标  
  22.     int x;  
  23.     int y;  
  24. };  
  25. int **Maze;     //初始化迷宫  
  26. point **Pre;    //保存任意点在路径中的前一步  
  27. point move[8]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};      //移动方向,横竖斜都可以,八个方向  
  28. void Create(int row,int column){  
  29.     //创建迷宫,注意到用0表示可走,1表示墙,将整个输入的迷宫再用墙围着,处理的时候就不用特别注意边界问题  
  30.     int i,j;  
  31.     for(i=0; i<row+2; i++)  
  32.         Maze[i][0] = Maze[i][column+1] = 1;  
  33.     for(j=0; j<column+2; j++)  
  34.         Maze[0][j] = Maze[row+1][j] = 1;  
  35.     for(i=1; i<=row; i++){  
  36.         for(j=1; j<=column; j++){  
  37.             cin>>Maze[i][j];  
  38.         }  
  39.     }  
  40. }  
  41. bool MazePath(int row,int column,int x,int y){  
  42.     //判断是否有路径从入口到出口,保存该路径(队列)  
  43.     if(x == row && y == column)return true;  
  44.     queue<point> q;     //用于广度优先搜索  
  45.     point now;          //当前位置  
  46.     now.x = x;  
  47.     now.y = y;  
  48.     q.push(now);  
  49.     Maze[now.x][now.y] = -1;  
  50.     while(!q.empty()){  
  51.         now = q.front();  
  52.         q.pop();  
  53.         for(int i=0; i<8; i++){  
  54.             if(now.x + move[i].x == row && now.y + move[i].y == column){  
  55.                 Maze[now.x + move[i].x][now.y + move[i].y] = -1;  
  56.                 Pre[row][column] = now;  
  57.                 return true;  
  58.             }  
  59.             if(Maze[now.x + move[i].x][now.y + move[i].y] == 0){  
  60.                 point temp;     //下个位置  
  61.                 temp.x = now.x + move[i].x;  
  62.                 temp.y = now.y + move[i].y;  
  63.                 q.push(temp);  
  64.                 Maze[temp.x][temp.y] = -1;  
  65.                 Pre[temp.x][temp.y] = now;  
  66.   
  67.             }  
  68.         }  
  69.     }  
  70.     return false;  
  71. }  
  72. void PrintPath(int row,int column){  
  73.     //输出最短路径  
  74.     point temp;         //保存位置  
  75.     stack<point> s;     //保存路径序列  
  76.     temp.x = row;  
  77.     temp.y = column;  
  78.     while(temp.x != 1 || temp.y != 1){  
  79.         s.push(temp);  
  80.         temp = Pre[temp.x][temp.y];  
  81.     }  
  82.     cout<<"(1,1)";  
  83.     while(!s.empty()){  
  84.         temp = s.top();  
  85.         cout<<' '<<'('<<temp.x<<','<<temp.y<<')';  
  86.         s.pop();  
  87.     }  
  88.     cout<<endl;  
  89. }  
  90. int main(){  
  91.     int t;          //用例数量  
  92.     int row;        //迷宫行数  
  93.     int column;     //迷宫列数  
  94.     cin>>t;  
  95.     while(t--){  
  96.         cin>>row>>column;  
  97.         Maze = new int*[row + 2];  
  98.         Pre = new point*[row + 2];  
  99.         for(int i=0; i<row+2; i++){  
  100.             Maze[i] = new int[column + 2];  
  101.             Pre[i] = new point[column + 2];  
  102.         }  
  103.         Create(row,column);  
  104.         if(MazePath(row,column,1,1)){  
  105.             cout<<"YES"<<endl;  
  106.             PrintPath(row,column);  
  107.         }  
  108.         else cout<<"NO"<<endl;  
  109.     }  
  110.     return 0;  

我的理解:DFS和BFS

DFS是深度优先,每一层找到一个满足的节点就往下一层找,该层其他满足的节点(未找)稍后再找其下一层,也就是子层优先同层,不满足就删掉该节点,从最深处往上,找上一层满足的节点,栈就可以满足这样一个特性。实际上是    先进后出  的特性。

BFS是广度优先,每一层找到所有满足的节点,对每个节点,再下一层,找到所有满足的节点,它是按照层遍历的,因此,需要把同层的其他满足的节点存储起来(或者说子层找到的满足条件的节点要等到上一层所有满足的节点做完同样的事情),因此,队列可以满足这样一个特性。实际上是    先进先出  的特性。

或者一个更加形象的例子,DFS就像要先满足儿子,后满足父亲的同辈(叔叔阿姨),这叫爱幼,后进先出的特性。BFS就像按辈分来,要等所有的叔叔阿姨吃饱了才轮到你吃,这叫尊老,是先进先出的特性。

还有为什么BFS找到的路径是最短路径?BFS是按照层来的,每层所有节点判断完全再往下一层,所以最先满足最终条件的节点,其深度最小,也就是路径最短。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值