迷宫问题——回溯法(栈)C++

迷宫问题——回溯法(栈)C++

思路:
从入口出发,顺某一方向向前探索,若能走通,则继续往前走;否则沿原路退回,换一个方向再继续探索,直至所有可能的通路都探索到为止。为了保证在任何位置上都能沿原路退回(回溯),显然需要用一个后进先出的结构来保存从入口到当前位置的路径。因此,在求迷宫通路的算法中要应用“栈”的思想。假设“当前位置”指的是“在搜索过程中的某一时刻所在图中某个方块位置”,则求迷宫中一条路径的算法的基本思想是:若当前位置“可通”,则纳入“当前路径”,并继续朝“下一位置”探索,即切换“下一位置”为“当前位置”,如此重复直至到达出口;若当前位置“不可通”,则应顺着“来向”退回到“前一通道块”,然后朝着除“来向”之外的其他方向继续探索;若该通道块的四周8个方块均“不可通”,则应从“当前路径”上删除该通道块。所谓“下一位置”指的是当前位置四周8个方向(上、下、左、右、左上、左下、右上、右下)上相邻的方块。假设以栈S记录“当前路径”,则栈顶中存放的是“当前路径上最后一个通道块”。由此,“纳入路径”的操作即为“当前位置入栈”;“从当前路径上删除前一通道块”的操作即为“出栈”。
数据结构设计考虑:
(1)建立二维数组表示迷宫的路径(0表示通道,1表示墙壁,数组矩阵增加外圈墙壁,保证每点都有8个移动方向);

1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 0 1 1 1 1
1 1 0 1 0 1 1 1 1 1
1 0 1 0 0 0 0 0 1 1
1 0 1 1 1 0 1 1 1 1
1 1 0 0 1 1 0 0 0 1
1 0 1 1 0 0 1 1 0 1
1 1 1 1 1 1 1 1 1 1

(2)创建一个栈,用来存储“当前路径”,即“在搜索过程中某一时刻所在图中某个方块位置”。
逻辑结构存储结构
(1)创建一个Int类型的二维数组int maze[n1][n2],用来存放0和1 ;
(2)创建一个结构体用来储存数组信息(数组的横坐标X,数组的纵坐标Y,方向C)
typedef struct node
{
int x;
int y;
int c;
}StackNode;

#include <iostream>
#include <stack>
using namespace std;
//栈节点 
typedef struct node
    {
        int x; //迷宫数组横坐标 
        int y;  //迷宫数组纵坐标 
        int c;  //前进方向 
    }StackNode;


//linkstack top[n1*n2];

//初始化迷宫数组 
const int xlen=6,ylen=8;  //xlen 行数,ylen 列数 
int maze[xlen+2][ylen+2]={
		{	1,	1,	1,	1,	1,	1,	1,	1,	1,	1},
		{	1,	0,	1,	1,	1,	0,	1,	1,	1,	1},
		{	1,	1,	0,	1,	0,	1,	1,	1,	1,	1},
		{	1,	0,	1,	0,	0,	0,	0,	0,	1,	1},
		{	1,	0,	1,	1,	1,	0,	1,	1,	1,	1},
		{	1,	1,	0,	0,	1,	1,	0,	0,	0,	1},
		{	1,	0,	1,	1,	0,	0,	1,	1,	0,	1},
		{	1,	1,	1,	1,	1,	1,	1,	1,	1,	1},
	};
int mark[xlen+2][ylen+2]; // 访问标记数组
StackNode path[xlen*ylen];  //存储访问路径 

struct Offsets {
 int a, b; // a和b是x,y方向的偏移
};
 
/*定义移动方向偏移 
(i,j)是当前位置
	   西北		   北         东北 
	(i-1,j-1)	(i-1,j)		(i-1,j+1)
西	(i  ,j-1)	(i  ,j)		(i  ,j+1)	东 
	(i+1,j-1)	(i+1,j)		(i+1,j+1)
	   西南		   南 		  东南 
*/
 
Offsets direction[8] = {
 {-1, 0}, // 北 0
 {-1, 1}, // 东北 1
 {0, 1}, // 东 2
 {1, 1}, // 东南 3
 {1, 0}, // 南 4
 {1, -1}, // 西南 5
 {0, -1}, // 西 6
 {-1, -1} // 西北 7
};
 


void Path(int x, int y, int m, int n)  //x, y为入口坐标;m,n为出口坐标
{
	int cur_i, cur_j, next_i, next_j;  //当前坐标(cur_i,cur_j),移动到下一位置坐标(next_i,next_j) 
	int d;//移动方向
	int k=0; 
	stack<StackNode> st; // 定义一个名为st的栈,栈中元素类型为 StackNode
	StackNode temp; 
	mark[x][y] = 1; // 标记入口地址已访问 
	temp.x=x;
	temp.y=y;
	temp.c=0 ;//从北开始 
	st.push(temp); // 把入口坐标进栈
	while(!st.empty()) 
	{ 
		temp = st.top(); // 取栈顶元素
 		st.pop(); // 栈顶元素出栈 
 		cur_i = temp.x;
 		cur_j = temp.y; // 取得当前位置坐标
 		d = temp.c; // 方向
 		while(d < 8) // 找下一位置(next_i,next_j) 
		{ 
 			next_i = cur_i + direction[d].a;
 			next_j = cur_j + direction[d].b;
 			if(next_i == m && next_j == n) // 到达出口
			{ 
 				while(!st.empty())    // 输出栈中存的路径
				{ 
 					temp=st.top();	// 取栈顶元素
					path[k].x = temp.x; 
					path[k].y = temp.y;
					path[k].c = temp.c;
 					st.pop(); // 出栈
 					k++;
 				}
				//输出路径 	
 				for(int i=k-1;i>=0;i--)
 				{
 					cout <<"(" <<path[i].x << "," << path[i].y << "), " << path[i].c << endl;
				}
 				cout << "(" << m << "," << n << "), " << d << endl;
				   
 				return;
 			}
			// 未到达出口
 			if(maze[next_i][next_j] == 0 && mark[next_i][next_j] == 0) // 如果通过且未被访问过
		    { 
 				mark[next_i][next_j] = 1; // 标记为已访问过
 				temp.x = cur_i;
 				temp.y = cur_j;
 				temp.c = d; // 记录已走过的位置和前进的方向
				st.push(temp); // 进栈
 				cur_i = next_i;
 				cur_j = next_j;
				d = 0; // 移动到(next_i,next_j),在各个方向试探
			}
			else d++; // 试探下一个方向
        } // 内while
    } // 外while
    cout << "没找到从入口到出口的路径!" << endl;
}


int main() 
{
 int i, j, x, y, m, n;   //x, y为入口坐标;m,n为出口坐标
 //初始化访问标记数组 
 for(i = 0; i < xlen; i++)
	for(j = 0; j < ylen; j++)
    {
		mark[i][j] = 0;
	}
 
 cout << "请输入入口位置坐标:";
 cin >> x >> y;
 cout << "请输入出口位置坐标:";
 cin >> m >> n;
 Path(x, y, m, n); // 调用求解迷宫问题函数 
 return 0;
}	

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值