DFS 的简单总结

DFS的小小总结

啥是DFS?

DFS简单讲叫深度优先搜索
举个例子
在这里插入图片描述

  • 这张图,如果用DFS怎么遍历呢?
    首先从根节点出发,也就是A节点开始,然后A - >B- > E,一直一条路走到底不回头,直到走到没路了。这时我们就回头,也叫回溯。然后E -> B,B -> F,然后又没路了,再回头到A -> C -> D - >A,结束。
    如图
    在这里插入图片描述
    路线 : A -> B -> E -> B -> F -> B -> A -> C -> A -> D -> A(大致如此,比较简陋,哈哈)
    DFS是一个很钻牛角尖的人,一路走到头,不撞南墙不回头。(太执着)
DFS的实现
  • 原理

    DFS是由栈的形式实现的,通过进行路径储存

    • 实现原理
      在这里插入图片描述
      如果不是很懂栈的话,就先学习一下栈,不然不好理解。
      通过对路径上的点进行统计,来实现回溯的作用
  • DFS的注意事项
  • 1 剪枝 剪枝是为了减少时间成本

  • 2 回溯 回溯回到原来路径

  • 3 还原 回到原来路径时,要还原现场

  • 来一道基础题
    马走日
    我发现这题加个O3优化快好多啊,感觉好神奇
    还是要吸口臭氧,0 - 0

#pragma GCC optimize(3)//吸口臭氧
#include<iostream>
#include<cstring>
using namespace std;
const int N=15;
int T,m,n,ans;
bool d[N][N];
int xx[]={2,1,-1,-2,-2,-1,1,2},yy[]={1,2,2,1,-1,-2,-2,-1};//马的方向数组
void dfs(int x,int y,int sum){
    if(sum==n*m){
        ans++;
        return ;
    }
    for(int i=0;i<8;i++){             //枚举马的方向
        int u=x+xx[i],v=y+yy[i];
        if(u<0||u>=n||v<0||v>=m) continue;//判断是否出界
        if(!d[u][v]){
            d[u][v]=true;
            dfs(u,v,sum+1);
            d[u][v]=false;//回溯和还原
        }
    }
}
int main(){
    cin>>T;
    for(;T;T--){
        int x,y;
        cin>>n>>m>>x>>y;
        memset(d,0,sizeof d);
        ans=0;
        d[x][y]=true;
        dfs(x,y,1);
        cout<<ans<<endl;
    }
    return 0;
}

  • 题目

八皇后经典问题

  • 代码
    为什么我们的代码没有栈,因为递归的本质就是通过栈来实现的,所以我们直接用递归就行了
#include<iostream>
#include<cstdio>
using namespace std;
const int N=15;
int n;
int path[N],ans;                 ///path数组存皇后
bool col[N],dg[N*2],udg[N*2];   ///col判断每一列的皇后
void dfs(int u){                ///dg和udg判断斜对角的皇后
    
    if(u==n){                      //判断是否已经排完
        ans++;
        if(ans<=3){
        for(int i=0;i<n;i++) printf("%d ",path[i]);
        puts("");
        }
        return ;
    }
    
    for(int i=1;i<=n;i++){
        if(!col[i]&&!dg[u+i]&&!udg[n-u+i]){
            col[i]=dg[u+i]=udg[n-u+i]=true;
            path[u]=i;
            dfs(u+1);
            col[i]=dg[u+i]=udg[n-u+i]=false;///还原现场
        }
    }
}
int main(){
    cin>>n;
    dfs(0);
    cout<<ans;
    return 0;
}

DFS需要大家自己去体会其中的奥秘,DFS的难点在剪枝排序,也没有固定用法


看一道例题 看看剪枝的重要性

DFS剪枝题

代码如下

#include<iostream>
#include<algorithm>
using namespace std;
const int N=25;
int n,m,ans=0x3f3f3f3f;
int c[N],cat[N];
bool cmp(int a,int b){ return a>b;}
void dfs(int u,int v){
    if(v>=ans) return ;
    if(u==n){
        ans=v;
        return ;
    }
    for(int i=0;i<v;i++)
        if(c[u]+cat[i]<=m){
            cat[i]+=c[u];
            dfs(u+1,v);
            cat[i]-=c[u];
        }
    cat[v]=c[u];
    dfs(u+1,v+1);
    cat[v]=0;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>c[i];
    sort(c,c+n,cmp);
    dfs(0,0);
    cout<<ans;
    return 0;
}

详细解析,点击这里

不是我不想写,是写的确是不好,大佬写的好详细

洪水灌溉算法(DFS)

这里还要介绍一个算法,那就是洪水灌溉算法(有点累,之后补充)
先给你们看个题

洪水灌溉算法 DFS

代码如下

#include<iostream>

using namespace std;
const int N=105;
char ch[N][N];
int n,m,ans;
int xx[]={-1,-1,-1,0,1,1,1,0},yy[]={-1,0,1,1,1,0,-1,-1};
void dfs(int x,int y){
    ch[x][y]='.';
    for(int i=0;i<8;i++){
        int u=x+xx[i],v=y+yy[i];
        if(u==0||v==0||u>n||v>m||ch[u][v]=='.') continue;
        dfs(u,v);
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>ch[i][j];
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
        if(ch[i][j]=='W'){
            dfs(i,j);
            ans++;
        }
    }
    cout<<ans;
    return 0;
}

不说了,继续补我BFS了,后面学好了,在发。
寒假一题里也有 传送门 -> 红与黑
萌新继续奋斗了,磕头磕头,大佬保佑
在这里插入图片描述

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值