回溯思想---迷宫问题(2)

题目如下:

在这里插入图片描述

做题历程:

看到题目时,第一个想法就是回溯,虽然出发点是对的,但是干了几个小时依然卡在了一个地方,就是标记的迷宫点是时刻变化的,当你这条路线走完后又要回到之前的点时,你标记的点又要从走过变为没有走过,回溯实际上就是参数传递再返回,而因为对回溯的不熟悉,不知道如何使标记变量在参数返回时跟着同步变化(真的想了好久啊),在最后实在想不出时看了资料,最后卡住的这点终于得到解决。

解题思路:

当确定S坐标后,从S坐标开始上下左右走,需要判断走的这点是否符合要求,如果符合要求,继续往下走,直到到达T点为止,记为一次走法,参数返回,从另一个分支开始走,若能到达T点,走法加1,参数再返回…
其中回溯有个特点是我之前不了解的,例如

void mylist(int p)
{
if() sum++;
for(int i=0;i<n;i++)
{
...
mylist(p)
...
}
}

当符合条件时,mylist() 会一直进行下去,但当条件不符合for()循环,结束时便会返回到前一个for()循环中,这样,就会执行mylist()下面的语句,这也是同步迷宫坐标标记和参数返回的关键点。

个人对回溯特点的理解即是:

只要符合条件就继续调用原来函数执行,当条件都不符合不能继续调用原函数时,返回到上一级往下执行语句。
就像一个小泥鳅,只要有洞就会往里面钻,钻到底后发现没洞了,就会往上爬在四周继续寻找洞口。
(接受反驳和建议)

解题代码:
#include<iostream>
#include<algorithm>
using namespace std;
struct walk
{
	int x;
	int y;
}S;   //记录点的坐标 
int t[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //上下左右四个方向,4行2列,0列代表x,1列代表y 
int n,m;  // 输入的n行m列,设置在外面方便调用,下面同理 
char s[100][100]; //用来记录迷宫各点 
int sum=0; //用来统计走法 
bool flag[100][100];  //用来标记该点走没走过 
void areval(walk p)   
{
	if(s[p.x][p.y]=='T') 
	{
		sum++;  //若有点的坐标与T坐标相等,则说明此走法可行,加1 
	}
	for(int i=0;i<4;i++)  //上左下右四个点 
	{
		walk q; //设一个新的点 
		q.x=p.x+t[i][0];
		q.y=p.y+t[i][1]; 
		if(q.x>=n||q.x<0||q.y>=m||q.y<0) continue;  //判断改点是否越界 
		if(s[q.x][q.y]=='#'||flag[q.x][q.y]!=true) continue;  //判断改点是否能走或者是否走过 
		flag[p.x][p.y]=false; //将原来的 p 点标记为走过 
		//cout<<"p["<<q.x<<"]["<<q.y<<"]\n";(用来观察点的走势) 
		areval(q); //不断调用回溯 
		flag[p.x][p.y]=true; //参数返回时使得原来的点恢复为未走过 
	}
}
int main()
{
	while(cin>>n>>m)
	{
		walk S,T;
		for(int i=0;i<n;i++)
		{
		for(int j=0;j<m;j++)
		{
		cin>>s[i][j];
		if(s[i][j]=='S')
		{
			S.x=i;S.y=j;
		}
		}
		}
		fill(&flag[0][0],&flag[n-1][m-1]+1,true); //先初始化,使该迷宫点都没走过 
		flag[S.x][S.y]=false; //标记初点,使其走过 
		areval(S);  //调用函数 
		if(sum==0) cout<<"impossible";
		else cout<<sum;
		sum=0;
		cout<<endl; 
	}
	return 0;
} 
感想:

几个小时只做了一题,在高中这个样子作业是写不完的,哈哈哈,不过收获确实也挺多的,之前做n皇后问题以为对回溯掌握了,但是其实只掌握了思路,但一些细节却没研究透彻,这题能完善我的理论,挺好。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回溯算法是一种经典的解决问题的算法,它的基本思想是在问题的解空间树中,按照深度优先的策略,从根节点出发搜索解空间树。当搜索到某个节点时,如果该节点不满足问题的约束条件,则回溯到该节点的父节点,继续搜索。迷宫问题回溯算法的一个经典应用,通过回溯算法可以生成迷宫并求解迷宫。 下面是C++实现迷宫的代码: 1.初始化迷宫 vector<vector<Point>> InitMaze(vector<vector<Point>> maze, int n) { //初始化迷宫 迷宫边缘赋0,其余处0,1间隔 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if ((i + j) % 2 == 0 && i != 0 && j != 0 && i != n - 1 && j != n - 1 && i % 2 != 0) { maze[i][j].x = i; maze[i][j].y = j; maze[i][j].value = 1; maze[i][j].flag = false; //用于判断之前是否已经到达过这个方块 } } } return maze; } 2.生成迷宫 void CreateMaze(vector<vector<Point>> &maze, int n) { stack<Point> s; Point cur; cur.x = 1; cur.y = 1; s.push(cur); while (!s.empty()) { cur = s.top(); s.pop(); if (cur.x == n - 2 && cur.y == n - 2) { break; } if (maze[cur.x][cur.y].flag) { continue; } maze[cur.x][cur.y].flag = true; int direction = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; random_shuffle(direction, direction + 4); for (int i = 0; i < 4; i++) { int next_x = cur.x + direction[i] * 2; int next_y = cur.y + direction[i] * 2; if (next_x >= 1 && next_x < n - 1 && next_y >= 1 && next_y < n - 1 && !maze[next_x][next_y].flag) { s.push(maze[next_x][next_y]); maze[(cur.x + next_x) / 2][(cur.y + next_y) / 2].value = 1; } } } } 3.求解迷宫 bool FindPath(vector<vector<Point>> &maze, int n, int x, int y) { if (x == n - 2 && y == n - 2) { maze[x][y].value = 2; return true; } if (maze[x][y].value == 0 || maze[x][y].flag) { return false; } maze[x][y].flag = true; if (FindPath(maze, n, x + 1, y) || FindPath(maze, n, x - 1, y) || FindPath(maze, n, x, y + 1) || FindPath(maze, n, x, y - 1)) { maze[x][y].value = 2; return true; } return false; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值