一.深度优先搜索
1. 搜索是指已知初始状态和目标状态,对问题的中间状态进行枚举的遍历的一种算法,通俗的讲,搜索就是比较复杂的枚举。
2.深度优先搜索是按照深度的方式进行搜索,就是把所有可行的方案都列举出来,不断的去尝试,直到找到问题的解。
设想你在一个迷宫里面,当我们在起点时,总要通过各种岔路口才能找到迷宫的终点,那么从起点开始,沿着一条路向前走,当碰到岔路口时,选择其中一个岔路前进。如果选择的这个岔路前方是一条死路,那么就退回这个岔路口,选择另一个岔路前进。如果岔路口存在新的岔路口,那么就按上述方法再次执行,这样的话,我们便可以找到终点。也就是说,当碰到岔路口时,总是以“深度”作为前进的关键,不碰到死胡同就不回头。
那么,碰到死胡同后返回上个岔路口的这种方法称之为——回溯法。
二.深度优先搜索之——回溯法。
1.回溯法是指从问题的某一角度出发,搜索所有的可能的情况,然后以其中的一种为新的出发点,继续向下探索,这样就走出了一条“路”,当这条路走到尽头时,返回上个出发点,从另外一种情况出发,继续搜索。及通过不断的“回溯”来寻找目标。
例:
数字的全排列:即123的全排列是123,132,213,231,312,321。即用1,2,3这三种数字组成一个3位数,且不允许出现重复的数字。
即如图所示,我们人为规定,1,2,3的选择方法是先选择1,再选2,最后选3。那么我们如果要进行全排列,便如图所示。
我们规定放第一个数字的是第一个盒子…以此类推,将数字放入盒子的代码:
void dfs(int step)
{
for(i=1;i<=n;i++) //一共有n个数字,在这里,n=3
{
if(book[i]==0) //等于0表示这个数字还未被放入盒子中
{
a[step]=i; //将数字i放在第step个盒子
book[i]=1;
dfs(step+1); //放下一个数字
book[i]=0;
}
}
return;
}
那么结束的标准是什么呢,即当我们处理到第n+1个小盒子时,说明前面的n个盒子已经放好了,那么我们变将这种情况输出。即:
if(step==n+1)
{
for(i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n");
return;
}
完整代码如下:
#include<stdio.h>
int a[10],book[10],n;
void dfs(int step)
{
int i;
if(step==n+1)
{
for(i=1;i<=n;i++) //将这种情况打印出来
printf("%d ",a[i]);
printf("\n");
return;
}
for(i=1,i<=n;i++)
{
if(book[i]==0)
{
a[step]=i;
book[i]=1;
dfs(step+1);
book[i]=0;
}
}
return;
}
int main()
{
scanf("%d",&n);
dfs(1);
return 0;
}
三.深搜的例题,走迷宫。
即我们用一个二维数组来储存这个迷宫,迷宫为n*m的大小,终点的坐标为(p,q),寻找从起点到终点的最短路径,我们规定顺序为向右走,向下,向左,向上。储存迷宫的二维数组中0代表可以走的路,1代表障碍物。
代码如下:
#include<stdio.h>
int n,m,p,q,min=1000000;
int a[20][20],book[20][20];
void dfs(int x,int y,int step) //x,y为当前点的横纵坐标,step表示已经走过的步数。
{
int next[4][2]={{0,1),{1,0},{0,-1},{-1,0}}; //分别为向右走,向下,向左,向上
int tx,ty,k; //tx,ty为下一个点的横纵坐标
if(x==p&&y==q) //判断是否到达终点
{
if(step<min)
min=step;
return;
}
for(k=0;k<=3;k++)
{
tx=x+next[k][0];
ty=y+next[k][1];
if(tx<1||tx>n||ty<1||ty>m)
continue;
if(a[tx][ty]==0&&book[tx][ty]==0)
{
book[tx][ty]=1;
dfs(tx,ty,step+1);
book[tx][ty]=0;
}
}
return;
}
int main()
{
int i,j,x,y;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]); //读入迷宫
scanf("%d %d %d %d",&x,&y,&p,&q); //读入起点和终点
book[x][y]=1; //标记起点已经走过了,防止重复走
dfs(x,y,0);
printf("%d ",min);
return 0;
}