首先我们先假设有一个4*6的迷宫,左上角为起点,右下角为终点。
"0”是通道,"1"是障碍物
而我们的目标则是寻找从起点到终点的最短路径
0,1,0,0,0,0,
0,0,0,1,0,0,
0,0,1,0,0,1,
1,1,0,0,0,0,
接着,我们把左上角作为坐标原点,建立坐标轴,向下为x轴,向右为y轴,然后我们在迷宫周围补一圈"0",让起点坐标为(1,1),最后把它存到数组中。
0,0,0,0,0,0,0,
0,0,1,0,0,0,0,
0,0,0,0,1,0,0,
0,0,0,1,0,0,1,
0,1,1,0,0,0,0,
那么我们应该怎么样才可以用代码表示位置的移动呢?
其实很简单,本质上,我们从起点向下移动一格,其实就是由坐标(1,1)变成(2,1)的过程,即(x+1,y+0)
那么向其他方向移动,也是同理
const int dirx[5] = {1, 0, -1, 0};
const int diry[5] = {0, 1, 0, -1};
const char dir[5] = {'D','R','U','L'};
// 我们定义到达的坐标为 tox,toy
// tox = x + dirx[i],toy = y + diry[i]
然后,我们还需要一个数组标记之前的路径,并且建立一个函数防止我们出现走出边界,走回头路,以及撞墙的情况。
const int row =4,col =6;
const int maxrc=6;
int maze[row+1][col+1]=
{
0,0,0,0,0,0,0,
0,0,1,0,0,0,0,
0,0,0,0,1,0,0,
0,0,0,1,0,0,1,
0,1,1,0,0,0,0,
};
int mins[maxrc+5][maxrc+5]; //标记每个位置的最小步数
int best = 1<<28; //最佳路径
char a[row*col+5]; //记录路径的方向
string stem;//最短的路径记录
bool judge(int x,int y){
if(x >= 1 && x <= row && y >= 1 && y <= col && maze[x][y] != 1)
return true;
return false;
}
到这里,dfs的全部准备活动就结束了。
我们进入正题
dfs又叫作深度优先搜索,在迷宫中就是要遍历所有可能的下个位置的坐标,再由下个坐标一直向深遍历搜索
for(int i =0;i < 4;i++){
int tox = x + dirx[i];
int toy = y + diry[i];
if(judge(tox,toy) && pos+1<=mins[tox][toy])
//保证不会出现回头路等情况,同时保证步数不会大于之前储存的最小步数。
{
maze[tox][toy] = 1; //标记当前位置已经走过
mins[tox][toy] = pos+1; //储存步数
a[pos] = dir[i]; //储存该pos的走的方向
dfs(tox,toy,pos+1);
maze[tox][toy] =0; //即将进入下层循环,回到该位置未走过的状态,取消标记
}
}
如果到达终点,则返回并存储数据。
if(x == row && y ==col ){
string s;
for(int i = 0; i < pos; i++ )
s += a[i]; //记录完整路径
if(pos < best){ //如果新路径小于上次记录的最佳路径,则更新
best = pos;
stem = s;
}
else if(pos == best && stem > s)
stem =s;
return ;
}
那么完整的dfs就是这样:
void dfs(int x,int y,int pos){
if(pos > best) //剪枝,减去没必要的操作
return ;
if(x == row && y ==col ){
string s;
for(int i = 0; i < pos; i++ )
s += a[i];
if(pos < best){
best = pos;
stem = s;
}
else if(pos == best && stem > s)
stem =s;
return ;
}
for(int i =0;i < 4;i++){
int tox = x + dirx[i];
int toy = y + diry[i];
if(judge(tox,toy) && pos+1<=mins[tox][toy])
{
maze[tox][toy] = 1;
mins[tox][toy] = pos+1;
a[pos] = dir[i];
dfs(tox,toy,pos+1);
maze[tox][toy] =0;
}
}
}
最后完整代码奉上
#include<iostream>
#include<cstring>
using namespace std;
const int dirx[5] = {1, 0, -1, 0};
const int diry[5] = {0, 1, 0, -1};
const char dir[5] = {'D','R','U','L'};
//向下x,向右y
const int row =4,col =6;
const int maxrc=6;
int maze[row+1][col+1]=
{
0,0,0,0,0,0,0,
0,0,1,0,0,0,0,
0,0,0,0,1,0,0,
0,0,0,1,0,0,1,
0,1,1,0,0,0,0,
};
int mins[maxrc+5][maxrc+5];
int best = 1<<28; //最佳路径
char a[row*col+5]; //记录路径的方向
string stem;//最短的路径记录
bool judge(int x,int y){
if(x >= 1 && x <= row && y >= 1 && y <= col && maze[x][y] != 1)
return true;
return false;
}
void dfs(int x,int y,int pos){
if(pos > best)
return ;
if(x == row && y ==col ){
string s;
for(int i = 0; i < pos; i++ )
s += a[i];
if(pos < best){
best = pos;
stem = s;
}
else if(pos == best && stem > s)
stem =s;
return ;
}
for(int i =0;i < 4;i++){
int tox = x + dirx[i];
int toy = y + diry[i];
if(judge(tox,toy) && pos+1<=mins[tox][toy])
{
maze[tox][toy] = 1;
mins[tox][toy] = pos+1;
a[pos] = dir[i];
dfs(tox,toy,pos+1);
maze[tox][toy] =0;
}
}
}
int main(){
memset(mins,1,sizeof(mins));
maze[1][1]=1;
dfs(1,1,1);
cout<<stem<<endl;
cout<<best-1<<endl;
return 0;
}