数据结构 | 空间 | 最短路 | |
DFS | stack | O(h) | 不具有最短性 |
BFS | queue | O( | 有最短路(所有边权重都一样时),常用于路径,迷宫等问题 |
一·DFS
回溯(恢复现场),剪枝,递归顺序很重要
dfe()
{
if()//满足条件记录或输出答案,不满足条件剪枝
for ()//遍历递归树该层的每种可能选择
{
//记录
dfs()//递归下一层递归树
//恢复现场
}
}
给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。
#include<algorithm>
#include<iostream>
using namespace std;
int n;
int vis[1000];
int a[10000];
void dfs(int x)
{
if (x > n)
{
for (int i = 1; i <= n; i++)
cout << a[i] << " ";
cout << endl;
return;
}
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
a[x] = i;
vis[i] = 1;
dfs(x + 1);
vis[i] = 0;//恢复现场
}
}
}
int main()
{
cin >> n;
dfs(1);
return 0;
}
n皇后问题
每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。
其中 .
表示某一个位置的方格状态为空,Q
表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
1.按行的全排列(枚举每行)
#include <iostream>
using namespace std;
const int N = 20;
int n;
char g[N][N];
bool col[N], dg[N * 2], udg[N * 2];
void dfs(int u)
{
if (u > n)
{
for (int i = 1; i <= n; i++)
puts(g[i]+1 );
puts("");
return;
}
for (int i = 1; i <= n; i++)
if (!col[i] && !dg[u - i + n] && !udg[u + i])
{
g[u][i] = 'Q';
col[i] = dg[u - i + n] = udg[u + i] = true;
dfs(u + 1);
col[i] = dg[u - i + n] = udg[u + i] = false;
g[u][i] = '.';
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = '.';
dfs(1);
return 0;
}
2.枚举每个位置放还是不放
#include <iostream>
using namespace std;
const int N = 20;
int n;
char g[N][N];
bool row[N],col[N], dg[N * 2], udg[N * 2];
void dfs(int x, int y, int s)
{
if (y > n) {
y = 1;
x++;
}
if (x > n)
{
if (s == n)
{
for (int i = 1; i <= n; i++)
puts(g[i] + 1);
puts("");
}
return;
}
//放
if (!row[x]&&!col[y] && !dg[x + y] && !udg[n + x-y])
{
g[x][y] = 'Q';
row[x]=col[y] = dg[x + y] = udg[n + x-y] = true;
dfs(x+1 , 1, s + 1);
g[x][y] = '.';
row[x]=col[y] = dg[x + y] = udg[n + x-y] = false;
}
//不放
dfs(x, y + 1, s);
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = '.';
dfs(1,1,0);
return 0;
}
二·BFS
初始状态入队列
while(队列不空){
取队头
拓展队头
}
给定一个 n×m的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1表示不可通过的墙壁。
最初,有一个人位于左上角 (1,1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。
数据保证 (1,1) 处和 (n,m) 处的数字为 0,且一定至少存在一条通路。
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef pair<int, int>PII;
const int N = 101;
int g[N][N];
int d[N][N];//存该点到起点距离
queue<PII>q;
int n, m;
int bfs()
{
q.push({ 0,0 });
d[0][0] = 0;
int dx[] = { -1,0,1,0 };
int dy[] = { 0,1,0,-1 };
while (!q.empty())
{
PII t = q.front();
q.pop();
for(int i = 0; i < 4; i++)
{
int x = dx[i] + t.first;
int y = dy[i] +t.second;
if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1)
{
d[x][y] = d[t.first][t.second] + 1;
q.push({ x,y });
}
}
}
return d[n - 1][m - 1];
}
int main()
{
cin >> n >> m;
memset(d, -1, sizeof(d);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> g[i][j];
}
}
cout << bfs() << endl;
return 0;
}