单源最短路 - Dijkstra 算法 / SPFA 算法

Dijkstra(迪杰斯特拉)算法是基于贪心思想的单源最短路算法

暴力 Dijkstra

具体如下:

struct node { int v, w; };
vector<node> e[N];
int dist[N], vis[N];

e[u] 存的是节点 u 的所有出边的终点和边权,dist[u] 存 u 到原点 s 的最小距离, vis[u] 标记是否走过

void dijkstra(int s) {
	memset(dist, 0x3f, sizeof dist);  // 初始先让所有点设为 +∞
	dist[s] = 0;  // 原点离自身距离为0
	for(int i = 1; i < n; i ++) {  // 枚举次数
		int u = 0;
		for(int j = 1; j <= n; j ++) {  // 枚举点
			if(!vis[j] && dist[j] < dist[u]) u = j;  // 选择一个距离最小的标记
		}
		vis[u] = 1;
		for(auto ed : e[u]) {  // 对u的所有出边,更新邻边v的最小距离
			int v = ed.v, w = ed.w;
			if(dist[v] > dist[u] + w) dist[v] = dist[u] + w;
		}
	}
}

主函数:

int main() {
	cin >> n >> m >> s;
	for(int i = 0; i < m; i ++) {
		cin >> a >> b >> c;
		e[a].push_back({b, c});  // 加入a的邻边b和权值c
	}
	dijkstra(s);
	return 0;
}

但是以上的方法对于负边权不适用,会出错;

并且时间复杂度为 O(n2+m)O(n2)

对于 n=103,m=106 AC, 而对于 n=106,m=106TLE;

Dijkstra 算法的堆优化 ---- 用优先队列维护被更新的点的集合

Heap - Dijkstra

具体如下:

priority_queue<pair<int, int>> q;

创建一个pair类型的大根堆 q{-距离, 点},或者是 小根堆 q{距离, 点}; 但小根堆需要自己用结构体加重载运算符

小根堆写法:

点击查看代码
struct node
{
    int first;  // 距离
    int second;  // 点编号
    bool operator <(const node &x)const  // 重载运算符
    {
        return x.first<first;
    }
};

priority_queue<node> q;
void dijkstra(int s) {
	memset(dist, 0x3f, sizeof dist);
	dist[s] = 0;
	q.push({0, s});  // 原点入队
	while(q.size()) {
		auto t = q.top();
		q.pop();
		int u = t.second;  // 从队头弹出距离最小的点u
		if(vis[u]) continue;  //如果走过就直接出队
		vis[u] = 1;  //没走过标记下
		for(auto ed : e[u]) {
			int v = ed.v, w = ed.w;
			if(dist[v] > dist[u] + w) {
				dist[v] = dist[u] + w;
				q.push({-dist[v], v});  // 把更小的点及距离入队
			}
		}
	}
}

SPFA 算法

  • 用于处理负边权的情况

具体如下:

void spfa(int s) {
    memset(d, 0x3f, sizeof d);
    d[s] = 0, vis[s] = 1;
    q.push(s);
    while(q.size()) {
        auto u = q.front();
        q.pop();
        vis[u] = 0;
        for(auto ed : e[u]) {
            int v = ed.v, w = ed.w;
            if(d[v] > d[u] + w) {
                d[v] = d[u] + w;
                if(!vis[v]) q.push(v), vis[v] = 1;  // v点被更新且不在队内,则入队
            }
        }
    }
}
  • 时间复杂度:O(kmnm)

总结:

暴力 Dijkstra Heap - Dijkstra SPFA
时间复杂度 O(n2) O(mlogm) O(kmnm)
图的大小 稠密图
m=O(n2)
稀疏图
m=O(n)
稠密图
m=O(n)
负边权 不能 不能
posted @   懒羊羊爱吃灰太狼  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示