递归——深度优先搜索(dfs)
区别与广度优先(bfs),深度优先注重的是一步走到底,通俗的举一个例子,比如一个迷宫,每走一格他就有很多的方向可以走,而深度优先就是先选取一个方向并且一路走到底直到触边或无路可走时再返回。以下使用递归方法实现深度优先搜索:
递归方法类似于栈,将数据一直递取到底后自下往上出栈。
大致框架如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| viod dfs(int k){ if(输出条件){ cout<< } else{ for(int i=0;i<n;i++){ if(vis[i]==0){ a[k]=数字,vis[i]=1 dfs(k+1); vis[i]=0; } } } }
|
下列题目方式解决一些排列组合问题。
组合输出 –5个数字组合输入3个盒子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include<bits/stdc++.h> using namespace std; int m,n,r; int a[200],vis[200];
int is_rise(int b[]){ int flag=1; for(int i=1;i<r;i++){ if(a[i]>a[i+1]){ flag=0; } } return flag; }
void dfs(int k){ if(k==r+1&&is_rise(a)){ for(int i=1;i<=r;i++){ cout<<a[i]<<" "; } cout<<"\n"; return; } for(int i=1;i<=n;i++){ if(vis[i]==0){ a[k]=i,vis[i]=1; dfs(k+1); vis[i]=0; } } } int main(){ cin>>n>>r; dfs(1); }
|
这题不用暴力for循环做解,而是考虑用三个盒子装入数字,装入过的数字用1标记箱子被使用。
素数环
eg:输入8 输出4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<bits/stdc++.h> using namespace std; int a[25],vis[25]; int n,cnt;
int isPrime(int x){ if(x<2)return 0; for(int i=2;i*i<=x;i++){ if(x%i==0)return 0; } return 1; }
void dfs(int k){ if(k==n+1 && isPrime(a[1]+a[n])){ cnt++; return; } for(int i=2;i<=n;i++){ if(vis[i]==0 && isPrime(i+a[k-1])){ a[k]=i,vis[i]=1; dfs(k+1); vis[i]=0; } } } int main(){ cin>>n; a[1]=1,vis[1]=1; dfs(2); cout<<cnt; }
|
全排列问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <bits/stdc++.h> using namespace std; int n; int a[25],b[25]; void dfs(int k){ if(k==n+1){ for(int i=1;i<=n;i++){ printf("%d ",a[i]); } printf("\n"); return; } for(int i=1;i<=n;i++){ if(b[i]==0){ a[k]=i,b[i]=1; dfs(k+1); b[i]=0; }} } int main(){ scanf("%d",&n); dfs(1); }
|
体积
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <bits/stdc++.h> using namespace std;
int n,cnt; int a[25],vis[1005];
void dfs(int k,int sum){ if(k==n+1){
vis[sum]=1; return; } dfs(k+1,sum+a[k]); dfs(k+1,sum); }
int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } dfs(1,0); for(int i=1;i<=1000;i++){ if(vis[i])cnt++; } cout<<cnt; return 0; }
|
若把上面代码的注释删除则可以得到:
1 2 3
| 3 1 3 4 8 4 5 1 7 3 4 0 6
|
由此可知上面深度搜索遍历的顺序是:
1 2 3 4 5 6 7 8
| 1+3+4 1+3 1+4 1 3+4 3 4 0
|
以上手写笔记逐个分析dfs递归情况,方便理解两个dfs同时出现的状态。
相当于第一个dfs一个一个出栈,出栈一个数据就进入下一个栈再进行递取。