一、DFS算法思想:
优先考虑深度,
换句话说就是一条路走到黑,不撞南墙不回头,直到无路可走的情况下,才会选择回头,然后重新选择一条路。
运用:回溯
对回溯不了解的,送上传送门——>回溯
二、先上基本的模板:
void dfs(int step){
if(step==总步数){ //step为抽象概念,具体中可能是sum、total、length等等
相关操作;
return ;
}
for(遍历每一种情况){
if(条件满足){
节点操作;
dfs(step+1);
撤销操作;
}
}
return ;
}
三、列题
学算法当然要刷题领悟啦,不然就是我这种一看就会(只是背了下来),一写就废的菜鸡 ^ - ^
下面就让我们一起看看这个俗称不撞南墙不回头算法都有哪些例题!!!
目前我遇到比较多的深搜大致可以分两类题:
第一种是挑选题:如排列组合,选数等。
另一种是”棋盘“题:如走迷宫/象棋/方阵,N皇后,数独等。
现在先后对两种题型分别上一道例题。
1、洛谷_[NOIP2002 普及组] 选数
思路:题目本质核心其实就是从n个数中挑选k个数,并且和为素数的组合有几种。如果是暴力的话,那就需要k层循环,而且k并不是给定值,所以我们就需要用dfs了。详细见代码。
#include<bits/stdc++.h>
using namespace std;
int n,k;long long a[25];long long cnt=0;
bool judgess(int i){ //判断素数
if(i==1) return false;
else{
for(int l=2;l<=sqrt(i);l++){
if(i%l==0) return false;
}
}
return true;
}
void dfs(int m,int sum,int startx){//m为已选的个数,sum为已选的和,startx为选数起始值
if(m==k){
if(judgess(sum)){
cnt++;
}
return;
}
for(int i=startx;i<n;i++){
dfs(m+1,sum+a[i],i+1);//此时挑选了a[i],挑选的数加1,和加a[i],选数范围下界加1(防止重复挑选)
}
return;
}
int main(){
cin>>n>>k;
for(int i=0;i<n;i++) cin>>a[i];
dfs(0,0,0);//初始选0个数,和为0,从下标为0开始
cout<<cnt<<endl;
return 0;
}
2、洛谷_单词方阵
思路:输入方阵时对'y'的位置进行标记,然后从'y'的坐标开始深搜。
dfs函数有四个参数:x1,y1为当前坐标,fx为搜索的方向,step记录搜索到低几个单词了;
如果step=7,那么说明能够顺利搜索到‘g',return 1;这时递归每一层的dfs都会返回1,就会对book进行标记,最后book标记的坐标都是要输出的单词,未被标记的输出’*‘。
#include<bits/stdc++.h>
using namespace std;
int n;char qp[101][101];int book[101][101];int a[10000][2],m=0;
int dx[8]={1,1,1,0,0,-1,-1,-1};
int dy[8]={-1,1,0,-1,1,0,-1,1};
char ans[8]="yizhong";
bool dfs(int x1,int y1,int fx,int step){ //x1,y1当前坐标,fx深搜方向,step为第几个字母
if(step>=7){
book[x1][y1]=1;return 1;
}
int u=x1+dx[fx], v=y1+dy[fx];
if(qp[u][v]==ans[step]){
if(dfs(u,v,fx,step+1)){
book[x1][y1]=1;return 1;
}
}
return 0;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>qp[i][j];
if(qp[i][j]=='y'){ //标记y的位置
a[m][0]=i;a[m][1]=j;m++;
}
}
}
for(int i=0;i<m;i++){ //遍历y的位置
int x=a[i][0],y=a[i][1];
for(int j=0;j<8;j++){ //遍历8个方向
if(dfs(x,y,j,1)) book[x][y]=1;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(book[i][j]==1) cout<<qp[i][j];
else cout<<"*";
}
cout<<endl;
}
return 0;
}
最后理论再多也是纸上谈兵,多练才是王道,推荐洛谷提单搜索系列题目——>传送门