基本描述
当一个问题无法解的时候,就需要回退一步 ,这就是回溯法
当然可以理解为传说中的后悔药 and 撤销;
这里需要说明 :游戏里经常使用回溯法 王者荣耀被对方这个老六 用某种组合技能 给挂了,是不是回到重生点 ?
你在社交软件里如果发送了你认为错误的信息的时候,需要点击撤销按钮 删除撤销的信息
算法的核心思想
当某个子问题, 无法继续 就得回退到前子问题 ,当然前子问题需要保存,用到的时候 回复,直到问题全部解决完毕
- 问题:需要解决的需求
- 保存前子问题: 栈
算法的思维导图模式
回溯算法的伪代码
回溯算法(解空间, 问题) {
往解空间添加子问题
while (解空间还有数据) {
需要回溯子问题 = 获取刚刚添加的新数据;
if (具体子问题 == 真) {
添加新的子问题
进入下一次循环
}
子问题操作
删除解空间的数据或者退出
}
}
回溯法 - 应用
迷宫求解
一共有多少种解法
首先在当前的位置设置为2(参考下面的流程图)
首先是向左走,如果能走得动设置迷宫的地图 并且更新这个位置
再向上走 ,如果能走得动设置迷宫的地图 并且更新这个位置
再向下走 ,如果能走得动设置迷宫的地图 并且更新这个位置
再向右走 ,如果能走得动设置迷宫的地图 并且更新这个位置
重复执行直到找到出口
迷宫求解流程图:
通过流程图可以清晰的每一个步骤
来看看代码吧:
迷宫求解 -声明
#ifndef __MAZESOLVING_H__
#define __MAZESOLVING_H__
struct MazePosition {
int x;
int y;
};
const int MapRow = 6;
const int MapCol = 6;
//迷宫求解 参数:迷宫地图 ,迷宫入口位置
void MazeSolving(const int Map[MapRow][MapCol],const MazePosition& MazeEntrance);
#endif
迷宫求解 -实现
#include "MazeSolving.h"
#include"SeqStack.h"
#include<iostream>
#include<cassert>
using namespace std;
const int MazeMapRow = MapRow;
const int MazeMapCol = MapCol;
struct Maze{
int map[MazeMapRow][MazeMapCol];
};
static void initMaze(Maze& maze,const int Map[MapRow][MapCol]) {
auto &mazeMap = maze.map;
for (int i = 0,j=0; i < MapRow; i++) {
for (j = 0; j < MapCol; j++) {
mazeMap[i][j] = Map[i][j];
}
}
}
static void showMaze(const Maze& maze) {
cout << "迷宫:" << endl;
for(auto &row: maze.map){
for (auto& col:row){
cout << "\t" << col << " ";
}
cout << endl;
}
cout << endl;
}
//检查入口是否合法
static bool CheckEntrance(const Maze& Maze, const MazePosition& current) {
const int Zreo = 0;
const int Once = 1;
const int Row = MazeMapRow - 1;
const int Col = MazeMapCol - 1;
auto& MazeMap = Maze.map;
const int& currentX = current.x;
const int& currentY = current.y;
return (((currentX == Zreo || currentX == Row) || (currentY == Zreo || currentY == Col)) && (MazeMap[currentX][currentY] == Once));
}
static bool CheckIsExit(Maze& Maze, const MazePosition& current, const MazePosition& MazePos) {
const int Zreo = 0;
const int Row = MazeMapRow - 1;
const int Col = MazeMapCol - 1;
const int& currentX = current.x;
const int& currentY = current.y;
const int& MazePosX = MazePos.x;
const int& MazePosY = MazePos.y;
return ((currentX != MazePosX || currentY != MazePosY) && ((currentX == Zreo || currentX == Row) || (currentY == Zreo || currentY == Col)));
}
static bool CheckNextPass(const Maze& Maze, const MazePosition& current, const MazePosition& next) {
bool ret = false;
const int Zreo = 0;
const int Row = MazeMapRow ;
const int Col = MazeMapCol ;
const int Once = 1;
const int& currentX = current.x;
const int& currentY = current.y;
const int& NextX = next.x;
const int& NextY = next.y;
const int& value = Maze.map[NextX][NextY];
if ((ret = ((NextX == currentX) && (NextY == currentY + 1 || NextY == currentY - 1)
|| (NextY == currentY) && (NextX == currentX + 1 || NextX == currentX - 1)))) {
ret = (((NextX >= Zreo || NextX < Row) || (NextY >= Zreo || NextY < Col)) && (value == Once));
}
return ret;
}
static bool FindMazeExit(Maze &Maze ,const MazePosition& MazeEntrance,MazePosition & MazeExitPos) {
assert(CheckEntrance(Maze, MazeEntrance) == true);
bool ret = false;
SeqStack stack;
initStack(stack);
MazePosition current = MazeEntrance;
MazePosition Next;
auto& MazeMap = Maze.map;
//走了一步
MazeMap[current.x][current.y] = 2;
push_Stack(stack, current);
while (!emptyStack(stack)) {
current = TopStack(stack);
//检测当前是否能退出
if (CheckIsExit(Maze,current, MazeEntrance)){
MazeExitPos = current;
ret = true;
break;
}
//检测左边
//检测下一个位置是否可以走
Next = current;
Next.y = current .y- 1;
//如果可以走
if (CheckNextPass(Maze,current,Next)){
//更新地图
MazeMap[Next.x][Next.y] = MazeMap[current.x][current.y] + 1;
//将下一个位置入栈
push_Stack(stack, Next);
//进入下一次循环
continue;
}
//检测上边
//检测下一个位置是否可以走
Next = current;
Next.x = current.x - 1;
//如果可以走
if (CheckNextPass(Maze, current, Next)) {
//更新地图
MazeMap[Next.x][Next.y] = MazeMap[current.x][current.y] + 1;
//将下一个位置入栈
push_Stack(stack, Next);
//进入下一次循环
continue;
}
//检测下边
//检测下一个位置是否可以走
Next = current;
Next.x = current.x + 1;
//如果可以走
if (CheckNextPass(Maze, current, Next)) {
//更新地图
MazeMap[Next.x][Next.y] = MazeMap[current.x][current.y] + 1;
//将下一个位置入栈
push_Stack(stack, Next);
//进入下一次循环
continue;
}
//检测右边
//检测下一个位置是否可以走
Next = current;
Next.y = current.y + 1;
//如果可以走
if (CheckNextPass(Maze, current, Next)) {
//更新地图
MazeMap[Next.x][Next.y] = MazeMap[current.x][current.y] + 1;
//将下一个位置入栈
push_Stack(stack, Next);
//进入下一次循环
continue;
}
//删除栈顶数据
pop_Stack(stack);
}
destroyStack(stack);
return ret;
}
void MazeSolving(const int Map[MapRow][MapCol], const MazePosition& MazeEntrance) {
Maze maze;
initMaze(maze,Map);
showMaze(maze);
MazePosition MazeExitPos;
if (FindMazeExit(maze, MazeEntrance,MazeExitPos)){
showMaze(maze);
cout << "找到迷宫的出口了 出口为:[" << MazeExitPos.x << "行," << MazeExitPos.y <<"列]" << endl;
}
else {
cout << "未找到迷宫出口" << endl;
}
}
运行结果: