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的难点在剪枝和排序,也没有固定用法
看一道例题 看看剪枝的重要性
代码如下
#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)
这里还要介绍一个算法,那就是洪水灌溉算法(有点累,之后补充)
先给你们看个题
代码如下
#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了,后面学好了,在发。
寒假一题里也有 传送门 -> 红与黑
萌新继续奋斗了,磕头磕头,大佬保佑