一、图上BFS
时间复杂度:O(m+n)
从图中的一个节点开始,一层一层往外搜索,每次都尝试访问同一层的节点,一层访问完再访问下一层。
对于边的长度固定的图,BFS找到的从起始节点到任意节点的路径都是到这个节点的最短路,路径长度就是起点到这个节点的距离。
从1号节点开始遍历整张图,此图中所有边的长度都为1。
先将1号节点加入BFS搜索队列,初始化时它的距离为0,其他节点的距离为无穷大或者-1。
接下来进行循环操作:
在队列中选择队首节点出队;
访问所有和它相邻的节点,如果此节点没有被访问过(仍为初始值),就将它加入队列,并且距离等于当前节点的距离加1;
直到队列为空。
const int INF = 0x3f3f3f3f;
const int N=1e5+10;
int n, m;
int dist[N];
queue<int> q;
vector<int> edge[N];
void bfs(int s) //s表示起点的编号
{
memset(dist, 0x3f, sizeof dist);
dist[s] = 0;
q.push(s);
while (!q.empty())
{
int x = q.front();
q.pop();
for (auto y : edge[x])
{
if (dist[y] == INF)
{
dist[y] = dist[x] + 1;
q.push(y);
}
}
}
}
二、网格图的BFS
typedef pair<int, int> PII;
const int N = 1e3+10;
const int M = 1e3+10;
const int INF = 0x3f3f3f3f;
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};
int n, m;
int dist[N][M];
char s[N][M];
queue<PII> q;
void bfs(int sx, int sy)
{
memset(dist, 0x3f, sizeof dist);
dist[sx][sy] = 0;
q.push({sx, sy});
while (!q.empty())
{
int x = q.front().first;
int y = q.front().second;
q.pop();
for (int i = 0; i < 4; i++)
{
int xx = x + dx[i];
int yy = y + dy[i];
if (xx < 1 || xx > n || yy < 1 || yy > m)
continue;
if (s[xx][yy] != 'X' && dist[xx][yy] == INF) //'X'表示障碍
{
dist[xx][yy] = dist[x][y] + 1;
q.push({xx, yy});
}
}
}
}
多源BFS
有多个起点和终点的图;
初始化多添加几个节点;
终止条件为抵达任一终点;
双向BFS
避免搜索节点过多的一种优化;
同时从终点和起点开始BFS;
当双向搜索到同一节点是即可停止;
三、图上DFS
从图中一个节点开始,每次寻找可以前往的下一个点,采用递归调用的方式进行下去的算法,要对其访问过的节点打上标记避免重复访问。
DFS过程中,在递归栈中存储的即为起始节点到当前节点的路径。在当前节点找不到新节点继续时,会向上回溯。
bool b[N];
vector<int> edge[N];
inline void dfs(int x)
{
b[x] = true;
for (auto y : edge[x])
{
if (!b[y])
dfs(y);
}
}
图上DFS是求解汉密尔顿通路问题(寻找一条从给定的起点到给定终点沿途恰好经过其他所有节点一次的路径)、汉密尔顿回路问题(寻找一条给定的起点除法,最后回到自己,沿途恰好经过其他所有节点一次的回路)、旅行商问题(寻找一条边权和最小的汉密尔顿回路)的基础算法。