DFS深搜刷题总结

一、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;
}

最后理论再多也是纸上谈兵,多练才是王道,推荐洛谷提单搜索系列题目——>传送门

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值