#4. 图的存储、最短路(未完结)
bro高一才开始自学图论(未完结警告)
图的存储
建议无脑用链式前向星
0x01. 什么是链式前向星
定义(摘自OI wiki)
本质上是用链表实现的邻接表
具体来说:
以有向边的形式 ,
加边操作:
void add (int u, int v, int w) { e[++tot].nxt = head[u]; e[tot].v = v; e[tot].w = w; head[u] = tot; }
找是否存在 到 的边:
bool find(int u, int v) { for(int i = head[u]; i; i = e[i].nxt) { if (e[i].v == v) { return true; } } return false; }
遍历一个节点连向的所有出边:
for(int i = head[u]; i; i = e[i].nxt){ int v = e[i].v, w = e[i].w; ... }
遍历图:
void dfs(int u) { if(vis[u]) return; vis[u] = true; for(int i = head[u]; i; i = e[i].nxt) { ... dfs(e[i].v); } }
0x02. 性质与复杂度
·可以通过每次多存一条反边来存储树或无向图,复杂度
·可以查询是否存在
·可以遍历点
·可以遍历整张图,复杂度
·空间复杂度
非负权图单源最短路: Dijkstra 算法
0x01. 算法思路
用
- 初始化起点
为 ,其他节点 为无穷大; - 找出未被遍历的,
值最小的 ,标记 ; - 扫描
所有出边 ,对于 ,若 则更新 ; - 重复
步骤直到所有节点被标记。
0x02. 算法实现与复杂度
P3371 【模板】单源最短路径(弱化版)
对于朴素的
AC代码:
#include<bits/stdc++.h> using namespace std; inline int read() { int f = 1, otto = 0; char a = getchar(); while(!isdigit(a)) { if(a == '-') f = -1; a = getchar(); } while(isdigit(a)) { otto = (otto << 1) + (otto << 3) + (a ^ 48); a = getchar(); } return f * otto; } const int maxn = 1e4 + 10; int n, m, s; struct edge{ int v, nxt, w; }e[maxn<<6]; int tot = 0, head[maxn]; void add(int u, int v, int w) { e[++tot].nxt = head[u]; head[u] = tot; e[tot].v = v; e[tot].w = w; } const int inff = 2147483647; int d[maxn]; bool vis[maxn]; void dijkstra() { for(int i = 0; i <= n; i++) d[i] = inff; d[s] = 0; for(int i = 1; i < n; i++) { int u = 0; for(int j = 1; j <= n; j++) { if(!vis[j] && (u == 0 || d[j] < d[u])) u = j; } vis[u] = 1; for(int i = head[u]; i; i = e[i].nxt) { int v = e[i].v, w = e[i].w; d[v] = min(d[v], d[u] + w); } } return; } int main() { n = read(), m = read(), s = read(); for(int i = 1; i <= m; i++) { int u = read(), v = read(), w = read(); add(u, v, w); } dijkstra(); for(int i = 1; i <= n; i++) { printf("%d ", d[i]); } return 0; }
P4779 【模板】单源最短路径(标准版)
发现每次找最小
使用STL库中的优先队列实现,每次以
AC代码:
#include<bits/stdc++.h> using namespace std; inline int read() { int f = 1, otto = 0; char a = getchar(); while(!isdigit(a)) { if(a == '-') f = -1; a = getchar(); } while(isdigit(a)) { otto = (otto << 1) + (otto << 3) + (a ^ 48); a = getchar(); } return f * otto; } const int maxn = 1e5 + 10; struct edge { int nxt, v, w; }e[maxn<<1]; int n, m, s; priority_queue<pair<int, int> >q; int tot = 0, head[maxn]; void add(int u, int v, int w) { e[++tot].nxt = head[u]; head[u] = tot; e[tot].v = v; e[tot].w = w; } const int inff = 2e9; int d[maxn]; bool vis[maxn]; void dijkstra() { for(int i = 1; i <= n; i++) d[i] = inff; d[s] = 0; q.push(make_pair(0, s)); while(!q.empty()) { int u = q.top().second; q.pop(); if(vis[u]) continue; vis[u] = 1; for(int i = head[u]; i; i = e[i].nxt) { int v = e[i].v; if(d[u] + e[i].w < d[v]) { d[v] = d[u] + e[i].w; q.push(make_pair(-d[v], v)); } } } return; } int main() { n = read(), m = read(), s = read(); for(int i = 1; i <= m; i++) { int u = read(), v = read(), w = read(); add(u, v, w); } dijkstra(); for(int i = 1; i <= n; i++) { printf("%d ", d[i]); } return 0; }
注意:不要盲目选择优先队列优化
可检测负环单源最短路: Bellman–Ford 算法(以及SPFA)
0x01. 算法思路
0x02. 算法实现与复杂度
P3371 【模板】单源最短路径(弱化版)
AC代码:
#include<bits/stdc++.h> using namespace std; inline int read() { int f = 1, otto = 0; char a = getchar(); while(!isdigit(a)) { if(a == '-') f = -1; a = getchar(); } while(isdigit(a)) { otto = (otto << 1) + (otto << 3) + (a ^ 48); a = getchar(); } return f * otto; } const int maxn = 1e4 + 10; const int maxm = 5e5 + 10; int m, n, s; struct edge{ int v, w, nxt; }e[maxm]; int tot = 0, head[maxn]; void add(int u, int v, int w) { e[++tot].nxt = head[u]; head[u] = tot; e[tot].v = v; e[tot].w = w; } const int inff = 2147483647; queue<int> q; int d[maxn]; bool vis[maxn]; void spfa() { for(int i = 1; i <= n; i++) d[i] = inff; d[s] = 0; vis[s] = 1; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = head[u]; i; i = e[i].nxt) { int v = e[i].v, w = e[i].w; if(d[v] > d[u] + w) { d[v] = d[u] + w; if(!vis[v]) vis[v] = 1, q.push(v); } } } } int main() { n = read(), m = read(), s = read(); for(int i = 1; i <= m; i++) { int u = read(), v = read(), w = read(); add(u, v, w); } spfa(); for(int i = 1; i <= n; i++) printf("%d ", d[i]); }
任意点对最短路: Floyd 算法
任意点对最短路:Johnson 算法
本文作者:Ydoc770
本文链接:https://www.cnblogs.com/Ydoc770/p/18454192
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步