DFS深度优先搜索 搜索用法: 对空间进行遍历
特点: 利用栈 stack
进行搜索,空间占用为 O(h) (h指树与图的高度)。尽量往子节点搜索,搜到头时回溯,同时查找是否能够进入其他子节点
例题: acwing842-排列数字
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 int path[N];bool st[N];void dfs (int u) { if (u == n) { for (int i = 0 ; i < n; i ++) cout << path[i] << " " ; cout << endl; return ; } for (int i = 1 ; i <= n; i ++) if (!st[i]) { path[u] = i; st[i] = true ; dfs (u + 1 ); st[i] = false ; } }
剪枝的典型例题: USACO1.5八皇后
解法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 char g[N][N];bool col[N], dg[N], udg[N];void dfs (int u) { if (u == n) { for (int i = 0 ; i < n; i ++) puts (g[i]); cout << endl; return ; } for (int i = 0 ; i < n; i ++) if (!col[i] && !dg[u + i] && !udg[n - u + i]) { g[u][i] = 'Q' ; col[i] = dg[u + i] = udg[n - u + i] = true ; dfs (u + 1 ); col[i] = dg[u + i] = udg[n - u + i] = false ; g[u][i] = '.' ; } }
解法2;
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 36 37 char g[N][N];bool row[N], col[N], dg[N], udg[N];void dfs (int x, int y, int s) { if (y == n) y = 0 , x ++; if (x == n) { if (s == n) { for (int i = 0 ; i < n; i ++) puts (g[i]); puts ("" ); } return ; } dfs (x, y + 1 , s); if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n]) { g[x][y] = 'Q' ; row[x] = col[y] = dg[x + y] = udg[x - y + n] = true ; dfs (x, y + 1 , s + 1 ); row[x] = col[y] = dg[x + y] = udg[x - y + n] = false ; g[x][y] = '.' ; } }
BFS宽度优先搜索 特点:利用队列 queue
进行搜索,空间占用为 O(2 ^h^)。同时搜索父节点下的每一个子节点,逐层递进。BFS搜索的特点是 具有最短性 (即到从父节点到子节点的最短路最先搜到) 注意BFS解最短路时只适用于每条路权重相同的情况
csdn - 宽度优先搜索图解
例题: acwing844-走迷宫
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 36 37 38 typedef pair<int , int > PII;int map[N][N], d[N][N];PII q[N * N]; int dx[4 ] = {-1 , 0 , 1 , 0 }, dy[4 ] = {0 , 1 , 0 , -1 };int bfs () { int hh = 0 , tt = 0 ; q[0 ] = {0 , 0 }; memset (d, -1 , sizeof d); d[0 ][0 ] = 0 ; while (hh <= tt) { auto t = q[hh ++]; for (int i = 0 ; i < 4 ; i ++) { int x = t.first + dx[i], y = t.second + dy[i]; if (x >= 0 && x < n && y >= 0 && y < m && !map[x][y] && d[x][y] == -1 ) { d[x][y] = d[t.first][t.second] + 1 ; q[ ++ tt ] = {x, y}; } } } return d[n - 1 ][m - 1 ]; }
若要存储路线:
1 2 3 4 5 6 7 8 9 10 11 12 13 PII Prev[N][N]; Prev[x][y] = t; int x = n - 1 , y = m - 1 ;while (x || y){ cout << x << ' ' << y << endl; x = Prev[x][y].first, y = Prev[x][y].second; }
树与图的存储