最短路

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+优先队列。

posted @ 2023-07-05 13:23  wuyoudexian  阅读(25)  评论(0)    收藏  举报