最短路
BFS求最短路
BFS可用于求无权图的最短路,时间复杂度为\(O(m)\),\(m\)为图上边的数量。
Floyd算法
Floyd算法用于求任意两点的最短路径,适用于任意图,无论有向无向,正权负权,它能一次性求出所用节点之间的距离。时间复杂度为\(O(n^3)\),\(n\)为节点数量。
设\(dp[i][j]\)是从\(i\)点到\(j\)的最短路径,最开始时每两个点之间的距离都为无穷大。则状态转移方程为\(dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])\)
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
需要注意的是,\(dp[i][i]\)的值应该为0,但是用这种方法求得的\(dp[i][i]\)并不为0。并且当\(dp[i][i]\)为负数时,说明存在负环。
Dijkstra算法
Dijkstra是一种单源最短路径算法,它能一次性求出一个起点到其它任意点的最短距离。时间复杂度为\(O(mlogn)\),\(m\)是边的数量,\(n\)是节点的数量。
把节点分为以确定最短路的集合\(S\)和未确定最短路的集合\(T\)。初始化起点\(s\)的最短路\(dis[s]\)为0,其它为正无穷。
用BFS扩展起点\(s\)的邻居节点,选择其中距离起点\(s\)最近的节点\(v\),如果\(v\)的邻居经过\(v\)中转,到起点\(s\)的距离更短,则更新其距离并放入集合\(T\)中。遍历完\(v\)的邻居节点后再把\(v\)放到集合\(S\)中,然后再从\(T\)中选择一个距离起点\(s\)最近的节点,重复以上操作,直到所有节点都被放入集合\(S\)中。
/*链式前向星*/
struct edge {
int to, nex, w;
};
int cnt;
array<edge, N> e;
array<int, N> head;
void add(int u, int v, int w) {
cnt++;
e[cnt].to = v;
e[cnt].w = w;
e[cnt].nex = head[u];
head[u] = cnt;
}
/*优先队列*/
struct node {
int dis, u;
bool operator <(const node &a) const {return dis > a.dis;}
};
array<int, N> dis;
array<bool, N> vis;
priority_queue<node> q;
/*dijkstra函数*/
void dijkstra(int s) {
dis[s] = 0;
q.push({0, s});
while(!q.empty()) {
int u = q.top().u;
q.pop();
if(vis[u]) continue;
vis[u] = true;
for(int i = head[u]; i; i = e[i].nex) {
int v = e[i].to;
if(dis[v] > dis[u] + e[i].w) {
dis[v] = dis[u] + e[i].w;
q.push({dis[v], v});
}
}
}
}
总的来说,Dijkstra算法就是BFS+优先队列。

浙公网安备 33010602011771号