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
    评论
DFS(Depth-First Search)即深度优先搜索,是一种常用的图遍历算法。在DFS中,我们从图的某个顶点开始,沿着一条路径尽可能深的搜索,直到无法继续为止,然后回溯到前一个节点,再继续搜索其他未访问的节点。 在C++中,我们可以使用递归或者栈来实现DFS算法。下面是一个使用递归实现DFS的示例代码: ```cpp #include <iostream> #include <vector> using namespace std; vector<vector<int>> graph; // 图的邻接表表示 vector<bool> visited; // 记录节点的访问状态 // 深度优先搜索函数 void dfs(int node) { visited[node] = true; // 标记当前节点为已访问 // 对于当前节点的所有未访问的邻居节点,递归调用dfs函数 for (int neighbor : graph[node]) { if (!visited[neighbor]) { dfs(neighbor); } } } int main() { int numNodes, numEdges; cin >> numNodes >> numEdges; // 初始化图的邻接表和访问状态数组 graph.resize(numNodes); visited.resize(numNodes, false); for (int i = 0; i < numEdges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); // 若为有向图则可省略这行 } int startNode; // 指定DFS的起始节点 cin >> startNode; dfs(startNode); // 输出所有已访问的节点 for (int i = 0; i < numNodes; i++) { if (visited[i]) { cout << i << " "; } } cout << endl; return 0; } ``` 在上述代码中,我们通过邻接表来表示图,并使用visited数组记录节点的访问状态。dfs函数按照深度优先的方式遍历图,递归调用自身来访问当前节点的邻居节点。最后,我们输出所有已访问的节点。 需要注意的是,DFS算法对于有环的图需要进行环的检测,以避免无限循环。另外,如果图是一个森林(由多个连通分量组成),我们需要对每个连通分量都执行DFS算法。 希望这个示例能帮助你理解DFS在C++中的实现。如果有任何疑问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值