一:BFS和DFS

  • 两者之间关于最短性和不具有最短性的区别,从顶点到最左下角的顶点,如果是BFS因为那条边的加入,最短路径是2,DFS的是4
  • DFS的空间复杂度很明显是树的高度决定,对于BFS很明显就是根据树的宽度决定的。

image.png

DFS的核心:递归边界,访问,递归循环,还原

二:DFS输出全排列

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 10; // 题目要求的
  4. int n;
  5. int path[N], st[N]; // path存储的实际输出的内容, st存储已经被使用的点
  6. void dfs(int s){
  7. if (s > n) // 这里根据main中dfs()传入的值确定
  8. {
  9. for (int i = 1; i <= n; i++) // dfs传入的初始值是0,i就需要从0开始遍历,因为传入的是1,从1开始遍历
  10. cout << path[i] << " ";
  11. cout << endl;
  12. return;
  13. }
  14. for (int i = 1; i <= n; i++) // 遍历所有的数字,看哪些数字没有使用过。
  15. {
  16. if (!st[i]) // st的作用就是看哪些没有用到
  17. {
  18. path[s] = i; // 注意下标是传入的s不是i
  19. st[i] = 1; // 用1标识这个数字已经用过了
  20. dfs(s + 1); // 下一位的选择
  21. st[i] = 0; // 回溯过程的体现,还原,path不用还原因为path就会被覆盖
  22. }
  23. }
  24. }
  25. int main()
  26. {
  27. ios::sync_with_stdio(false);
  28. cin >> n;
  29. dfs(1);
  30. return 0;
  31. }

三:DFS之N-皇后问题

image.png
image.png
首先弄清楚,如果使用下标从0开始,输出的时候不能用puts(p[i]),因为输出总是有问题,puts输出没办法控制二维,只能傻瓜式输出一维,而且puts括号内只能是指针或者数组名,puts输出的内容只要遇到/0的时候就输出错误,这也是如果初始化的时候,如果只初始化二维的第二个元素,0号位置的不管,通过puts的时候输出失败的原因。
image.png

  • 还要注意的就是斜线跟横纵坐标的关系,跟下标从什么开始也不太一样,反斜线也是有一定关系的(下标0开始:列+ n - 行 )。
  • 本质的递归边界,访问,递归,还原没有变,但是传递的起始值是发生变化的
  1. #include <iostream>
  2. using namespace std;
  3. const int N = 20; // 斜对角线的数目是行、列的 2n - 1
  4. char g[N][N];
  5. bool col[N], dg[N], udg[N]; // col记录列占用,dg记录\对角线,udg记录/对角线
  6. int n;
  7. void dfs(int u)
  8. {
  9. if (u == n)
  10. {
  11. for (int i = 0; i < n; i++) puts(g[i]); // 可以通过输出一维元素输出内容
  12. puts("");
  13. return;
  14. }
  15. for (int i = 0; i < n; i++)
  16. {
  17. if (!col[i] && !dg[i + u] && !udg[i - u + n]) // 当前列,斜线,反斜线全部都没有被占用
  18. {
  19. col[i] = dg[i + u] = udg[i - u + n] = true;
  20. g[u][i] = 'Q';
  21. dfs(u + 1);
  22. col[i] = dg[i + u] = udg[i - u + n] = false;
  23. g[u][i] = '.';
  24. }
  25. }
  26. }
  27. int main()
  28. {
  29. cin >> n;
  30. for (int i = 0; i < n; i++)
  31. for (int j = 0; j < n; j++)
  32. g[i][j] = '.';
  33. dfs(0);
  34. return 0;
  35. }

四:BFS

  • 迷宫问题如果使用深度优先搜索的话,能保证搜到,但是不能保证搜到的路径是最短的。
  • 需要注意BFS虽然可以解决最短路,但是局限性在于只能解决所有边权都是1的时候

image.png

  • memset的初始化image.png
  • 基本思路就是把g图中所有的0的点依次放入队列q中,然后计算出每个点到起点的距离,因为最终只需要最右下角的点,所以只需要返回d[n - 1][m - 1];
  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. typedef pair<int, int> PII; // 用来存储x, y
  5. const int N = 110;
  6. int g[N][N], d[N][N]; // g存储整个图形,d存储图中为0的点到原点的距离
  7. PII q[N * N]; // 作为队列,一次放入所有的0的点,计算距离
  8. int n, m;
  9. int bfs()
  10. {
  11. int hh = 0, rr = 0;
  12. memset(d, -1, sizeof d); // memset初始化的时候,sizeof d就是按照d一个元素大小初始化,最小是字节
  13. d[0][0] = 0; // 起始点距离肯定是0
  14. q[0] = {0, 0}; 队列自然存储的是第一个点的坐标
  15. int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1}; // 某个点上下左右四个点的坐标
  16. while (hh <= rr)
  17. {
  18. auto u = q[hh++];
  19. for(int i = 0; i < 4; i++)
  20. {
  21. int x = u.first + dx[i], y = u.second + dy[i];
  22. if (x >= 0 && x < n && y >= 0 && y < m && d[x][y] == -1 && g[x][y] == 0) // 前四个条件不能越界,后面是g必须是0,而且距离是没有被计算
  23. {
  24. d[x][y] = d[u.first][u.second] + 1;
  25. q[++rr] = {x, y};
  26. }
  27. }
  28. }
  29. return d[n - 1][m - 1];
  30. }
  31. int main()
  32. {
  33. cin >> n >> m;
  34. for (int i = 0; i < n; i++)
  35. for (int j = 0; j < m; j++)
  36. cin >> g[i][j];
  37. cout << bfs() << endl;
  38. return 0;
  39. }