P3008 [USACO11JAN] Roads and Planes G(dij + 拓扑排序)
发现单向航线存在负边权,不能直接跑 dij
而双向的道路保证为正边权,可以在道路中跑 dij,想到把道路进行类似“缩点”的操作,把直接相连的道路看做连通快
那么在连通快这样的团之间,有航线相连,且航线满足一个很好的性质:若存在 x -> y,则不可能存在 y -> x,即无环
那团与航线所成的图就是一个含负边权的 DAG
后来发现 DAG 上求单源最短路,可以直接做一遍拓扑排序扫描
code
inline void topsort() { memset(dist, 0x3f, sizeof(dist)); for (int i = 1; i <= n; i ++) if (!in[i]) q.push(i); while (!q.empty()) { int x = q.front(); q.pop(); for (int i = h[x]; i; i = e[i].next) { int y = e[i].to, w = e[i].w; dist[y] = min(dist[y], dist[x] + w); if (--in[y] == 0) q.push(y); } } }
所以,思路就很直观了,对道路预处理出连通快,总的对团与航线层次做拓扑排序,再在其中每次的连通快内的层次做 dij,不过实际实现还有很多细节要注意
算法复杂度瓶颈就是 dij,整个做法也就是
#include <bits/stdc++.h> #define re register int using namespace std; typedef pair<int, int> pii; const int N = 3e4 + 10, M = 2e5 + 10, inf = 0x3f3f3f3f; struct edge { int to, w, next; }e[M]; int top, h[N]; int dist[N], in[N], id[N], idx; int n, mr, ml, s; bool vis[N]; vector<int> block[N]; queue<int> tp; priority_queue< pii, vector<pii>, greater<pii> > q; inline void add(int x, int y, int w) { e[++ top] = (edge){y, w, h[x]}; h[x] = top; } void dfs(int u, int uid) { id[u] = uid; block[uid].push_back(u); for (int i = h[u]; i; i = e[i].next) { int v = e[i].to; if (!id[v]) dfs(v, uid); } } inline void dijkstra(int xid) { for (re i = 0; i < block[xid].size(); i ++) { int x = block[xid][i]; q.push(make_pair(dist[x], x)); } while (!q.empty()) { int x = q.top().second; q.pop(); if (vis[x]) continue; vis[x] = true; for (re i = h[x]; i; i = e[i].next) { int y = e[i].to, w = e[i].w; if (dist[y] > dist[x] + w) { dist[y] = dist[x] + w; if (id[x] == id[y]) q.push(make_pair(dist[y], y)); } if (id[x] != id[y] && -- in[id[y]] == 0) tp.push(id[y]); } } } inline void topsort() { for (re i = 1; i <= n; i ++) dist[i] = inf; dist[s] = 0; for (re i = 1; i <= idx; i ++) if (in[i] == 0) tp.push(i); while (!tp.empty()) { int x = tp.front(); tp.pop(); dijkstra(x); } } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> mr >> ml >> s; while (mr --) { int a, b, c; cin >> a >> b >> c; add(a, b, c); add(b, a, c); } for (int i = 1; i <= n; i ++) if (!id[i]) { idx ++; dfs(i, idx); } while (ml --) { int a, b, c; cin >> a >> b >> c; add(a, b, c); in[id[b]] ++; } topsort(); for (re i = 1; i <= n; i ++) if (dist[i] > N * 10000) cout << "NO PATH\n"; else cout << dist[i] << '\n'; return 0; }
分类:
C 图论 - 最短路
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具