回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”
在生活中,也会出现回溯方法的运用,比如我们有些没有反向感的朋友们,去西安玩耍,走到钟楼底下环形通道迷路了,想要找到7出口,又不知道其他路径可行的情况下,就会原路返回到原点,继续探索可行的路径,知道找到出口位置。这就是回溯法在生活中的例子,
在数据结构中,也也会用到回溯法 ,比如在解决迷宫问题上,回溯法就粉墨登场了,
在迷宫中,从入口点进去,寻找出口,就像我们在钟楼环形通道寻找7出口一样,当眼前有几条路径可以走时,就会开始探测着走,如果是出口,就走出迷宫,如果不是出口,就回退到刚才的位置,继续探测,直到找到出口。
下面是具体代码的实现(该迷宫不带环,且只有一条通路)
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "maze.h"
//初始化迷宫地图
void MazeInit(Maze* m,int map[COL][ROW])
{
//迷宫为空,直接返回
if(m==NULL)
{
return ;
}
size_t i=0;
//初始化迷宫
for( ;i<COL;i++)
{
size_t j=0;
for( ;j<ROW;j++)
{
m->_map[i][j]=map[i][j];
}
}
return ;
}
//迷宫打印
void MazePrint(Maze *m,int map[COL][ROW])
{
if( m==NULL)
{
return ;
}
size_t i=0;
//开始打印迷宫
for( ;i<COL;i++)
{
size_t j=0;
for( ;j<ROW;j++)
{
printf(" %2d",m->_map[i][j]);
}
//一行打印完毕,准备换行
printf("\n");
}
printf("\n");
return ;
}
//开始走迷宫
void GetPath( Maze* m,Point entry)
{
if( m==NULL)
{
return;
}
//利用此函数帮我们完成递归
_GetPath( m,entry,entry);
}
走迷宫基础框架
//利用该函数完成递归
void _GetPath(Maze* m,Point cur,Point entry)
{
//1.判断当前点能否能落脚
if(!CanStay(m,cur))
{
return;
}
printf("cur:(%d,%d)\n",cur.x,cur.y);
//2.若能落脚,给当前位置坐标记为2
Mark(m,cur);
//3.若当前点为出口,说明找到了一条出路,探测就结束
if(Exit(m,cur,entry))
{
printf("找到了一条出路\n");
return;
}
//4。若当前点不是出口,按顺时针顺序探测四个方向的相邻点
//向上探测(纵坐标不变,横坐标减1)
Point up=cur;
up.x-=1;
_GetPath( m,up,entry);
//向右探测(横坐标不变,纵坐标加1)
Point right=cur;
right.y+=1;
_GetPath( m,right,entry);
//向下探测(纵坐标不变,横坐标加1)
Point down=cur;
down.x+=1;
_GetPath( m,down,entry);
//向左探测(横坐标不变,纵坐标减1)
Point left=cur;
left.y-=1;
_GetPath( m,left,entry);
}
下面是每个函数的具体实现
//判断该点是否是出口
int Exit(Maze* m,Point cur,Point entry)
{
//当前点是入口,不是出口,返回0
if(cur.x==entry.x&&cur.y==entry.y)
{
return 0;
}
//如果该点在边界上,且不是入口,则一定是出口,返回1
if(cur.x==0||cur.y==0||cur.x==COL-1||cur.y==ROW-1)
{
return 1;
}
return 0;
}
//标记当前点为2
void Mark( Maze* m,Point cur)
{
if( m==NULL)
{
return ;
}
m->_map[cur.x][cur.y]=2;
}
//判断当前点是否可以落脚
int CanStay( Maze* m,Point cur)
{
//该点在地图外,返回0
if(cur.x<0||cur.x>=COL||cur.y<0||cur.y>=ROW)
{
return 0;
}
//该点在地图内
//是1就可以落脚,返回1,2,0均不可以落脚
int value=m->_map[cur.x][cur.y];
if( value==1)
{
return 1;
}
//2,0均不可以落脚,返回0
return 0;
}
测试代码
#include <stdio.h>
#include "maze.h"
#define TESTLINE printf("\n=========%s=========\n ",__FUNCTION__);
void TestInit( )
{
TESTLINE;
int map[COL][ROW]={
{0,1,0,0,0,0},
{0,1,1,1,0,0},
{0,1,0,1,0,0},
{1,1,0,1,1,0},
{0,0,0,0,0,0}
};
Maze maze;
MazeInit(&maze,map);
MazePrint(&maze,map);
Point entry;
entry.x=0;
entry.y=1;
GetPath(&maze,entry);
}
int main( )
{
TestInit( );
return 0;
}
将走过的路径打印出来