深搜简介
深搜是一种对数串或图形进行遍历的算法。它会从起点像树状图一样向下进行探索,如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底 ,这种尽量往深处走的概念即是深度优先的概念。回溯是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
深度优先搜索是对图进行搜索的算法,目的也都是从起点开始搜 索直到到达指定顶点(终点)。深度优先搜索会沿着一条路径不断往下搜索直到不能再继续为止,然后再折返,开始搜索下一条候补路径。
深搜大概可以分为两种:
全排列问题
一种需要将规定条件下的所有情况输出的问题
就是填空,要输出的东西是一个个空,每次用循环来枚举填的空的范围,找到符和要求的数,从而填空。填完一个空又去填下一个空。
经典例题:
题目描述
输出自然数1~n所有不重复的排列,即n的全排列,要求所产生的任一数字序列中不允许出现重复数字。
输入
1<=n<=9
输出
由1~n组成的所有不重复的数字序列。每行一个序列
样例输入
3
样例输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
代码
#include <bits/stdc++.h>
using namespace std;
bool a[11];
int b[11];
int n;
void out()
{
for(int i=1;i<=n;i++)
{
cout<<b[i]<<" ";
}
cout<<endl;
}
void dfs(int i)
{
for(int j=1;j<=n;j++)//枚举填的范围
{
if(a[j]==0)
{
b[i]=j;
a[j]=1;
if(i==n)//填完了
{
out();//输出
}
else
{
dfs(i+1);
}
a[j]=0;//回溯(重点⭐⭐⭐)
}
}
}
int main()
{
cin>>n;
dfs(1);//该填的位数
return 0;
}
迷宫类问题
题目描述
给定一个迷宫和其中的障碍(可有可无),在迷宫内按规定走法四处乱走。如果走不通,则需要返回,进行恢复现场,直到走到终点。最经典的莫过于走迷宫问题(有障碍):
给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过。给定起点坐标和终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
输入
第一行N、M和T,N为行,M为列,T为障碍总数。第二行起点坐标SX,SY,终点坐标FX,FY。接下来T行,每行为障碍点的坐标。
输出
给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方案总数。
样例输入
2 2 1
1 1 2 2
1 2
样例输出
1
提示
【数据规模】
1≤N,M≤5
代码
#include <bits/stdc++.h>
using namespace std;
bool a[7][7],l[7][7];
int x,xx,y,yy,za,zi;//N、M和T,N为行,M为列,T为障碍总数。起点坐标:x,xx 终点坐标y,yy。za,zi是障碍物的坐标。
int n,m,t,ans;
void s(int w,int q)
{
if(w>n||q>m||w<1||q<1||a[w][q]==1||l[w][q]==1)//如果出界或起始点不在界内或在障碍物上或走到之前走过的地方
{
return;//返回上一位
}
if(w==y&&q==yy)//到了终点
{
ans++;
return;
}
l[w][q]=1;//将之前走过的地方标记
s(w+1,q);//向四周走
s(w-1,q);
s(w,q+1);
s(w,q-1);
l[w][q]=0;//回溯(重点⭐⭐⭐)
return;
}
int main()
{
cin>>n>>m>>t>>x>>xx>>y>>yy;
for(int i=1;i<=t;i++)
{
cin>>za>>zi;
a[za][zi]=1;//标记
}
s(x,xx);
cout<<ans;
return 0;
}
特殊迷宫类问题:
数塔问题
题目描述
有形状如图所示的数塔,从顶部出发,在每一结点可以选择向左走或是向右走,一起走到底层,要求找出一条路径,使路径上的值的和最大。
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输入
第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
输出
输出可能得到的最大和
样例输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出
max=30
提示
用二维数组存储的时候不需要管空格,如样例那样存储就可以了。
代码
#include <bits/stdc++.h>
using namespace std;
int n,maxx,ans;
int t[110][110];
void s(int x,int y,int k)
{
k=k+t[x][y];//加上走过的路上的数
if(x==n)
{
if(maxx<k)
{
maxx=k;
}
return;
}
s(x+1,y,k);
s(x+1,y+1,k);
k=k-t[x][y];//回溯(重点⭐⭐⭐)
return;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)//每行都比上一行多一格
{
cin>>t[i][j];
}
}
s(1,1,0);
cout<<"max="<<maxx;
return 0;
}