区别与联系
区别
DFS多用于连通性问题因为其运行思想与人脑的思维很相似,故解决连通性问题更自然,采用递归,编写简便(但我个人不这样觉得。。。)
DFS的常数时间开销会较少。所以对于一些能用DFS就能轻松解决的,为何要用BFS?
一般来说,能用DFS解决的问题,都能用BFS。
BFS多用于解决最短路问题,其运行过程中需要储存每一层的信息,所以其运行时需要储存的信息量较大,如果人脑也可储存大量信息的话,理论上人脑也可运行BFS。
Backtracking相当于在DFS的基础上进行剪枝。
联系
BFS(显式用队列)
DFS(隐式用栈)(即递归)
当然,对于DFS,用递归可能会造成栈溢出,所以也可以更改为显示栈。
模板
在解答树里进行考虑
DFS/Backtracking
1 void dfs(int 当前状态) 2 { 3 if(当前状态为边界状态) 4 { 5 记录或输出 6 return; 7 } 8 for(i=0;i<n;i++) //横向遍历解答树所有子节点 9 { 10 //扩展出一个子状态。 11 修改了全局变量 12 if(子状态满足约束条件) 13 { 14 dfs(子状态) 15 } 16 恢复全局变量//回溯部分 17 } 18}
BFS
void bfs() { q.push(s); //将(起始)首节点加入队列 visited[s]=true; //标记首节点已经被访问 while(!q.empty()) { int x=q.front(); q.pop(); 遍历 x 的各个Next状态 next { if(next is legal) q.push(next); //入队,同时计数或维护等; } } }
DFS(非递归,显式用栈)
1 //求(sx,sy)到(ex,ey)的其中一条路径 2 //如果无法到达,返回false 3 bool dfs() 4 { 5 stack<P>s; 6 vis[sx][sy] = true; //访问 7 s.push(P(sx, sy)); //入栈 8 while (!s.empty()) //栈不为空。继续搜索;为空了还没有得到路径,说明无解 9 { 10 P p = s.top(); 11 int x = p.first, y = p.second; 12 if (x == ex && y == ey) 13 { 14 while (!s.empty()) 15 { 16 //打印结果,或进行其它操作 17 P p = s.top(); s.pop(); 18 printf("%d %d\n", p.first, p.second); 19 } 20 return true; 21 } 22 int flag = false; //记录是否进入“死胡同” 23 for(遍历相邻的状态) 24 { 25 if(满足条件) 26 { 27 vis[nx][ny] = true; 28 s.push(P(nx, ny)); 29 flag = true; 30 break; //DFS,选择其中一条路走 31 } 32 } 33 if (!flag) 34 s.pop(); //周四是墙或已走过,回溯,也就是不断出栈,知道新的栈顶元素有其他出路 35 } 36 return false; 37 }
经典例题
部分和问题(DFS+剪枝)
给定整数a1、a2、...an,判断是否可以从中选出若干个数字,使它们的和恰好为k。(1≤n≤20)
1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 20 + 10; 7 int n, a[maxn], k; 8 int vis[maxn]; 9 10 //已经从前cur项得到和sum 11 bool dfs(int cur, int sum) 12 { 13 if (sum > k) return false; //剪枝 14 if (cur == n) return sum == k; //如果前n项都计算过了,则返回sum是否等于k 15 16 //不加上a[i]的情况 17 if (dfs(cur + 1, sum)) return true; 18 //加上a[i]的情况 19 if (dfs(cur + 1, sum + a[cur])) return true; 20 21 //无论是否加上a[i]都不能凑成k,则返回false 22 return false; 23 } 24 25 int main() 26 { 27 while (scanf("%d%d", &n, &k) == 2 && n) 28 { 29 for (int i = 0; i < n; i++) 30 scanf("%d", &a[i]); 31 if (dfs(0, 0)) printf("YES\n"); 32 else printf("NO\n"); 33 } 34 return 0; 35 }