最短路 P1629 邮递员送信 【反向图求最短路】
题目
https://www.luogu.com.cn/problem/P1629
题目分析
题目大意就是求节点1到各个点的最短路径以及各个点到节点1的最短路径,最后求和。
节点1到各个点的最短路径:使用Dijkstra+堆优化即可实现(传送门)
但是各个点到节点1的最短路径如何求?
这里注意:题目中的图是单向图,也就是说我们可以将求此图中的各个点到节点1的最短路径转换为求此图的反向图中的节点1到各个点的最短路径,这二者是等价的
所以简单的方法就是两套Dijkstra——堆优化,一个在原图进行,一个在反向图中进行
最后求和即可
代码
#include<iostream> #include<cstdio> #include<queue> using namespace std; #define maxn 1002 #define maxm 100002 #define inf 0x3f3f3f3f int n, m; struct edge { int to; int dis; int next; }; struct node { int dis; int pos; }; bool operator <(const node &a, const node &b) { return a.dis > b.dis; } edge e[maxm],e2[maxm]; int head[maxn], dist[maxn], cnt=0, visited[maxn]; int head2[maxn], dist2[maxn], cnt2 = 0, visited2[maxn]; priority_queue<node>q, q2; void addedge(int u,int v,int w) { cnt++; e[cnt].to = v; e[cnt].dis = w; e[cnt].next = head[u]; head[u] = cnt; } void addedge2(int u, int v, int w) { cnt2++; e2[cnt2].to = v; e2[cnt2].dis = w; e2[cnt2].next = head2[u]; head2[u] = cnt2; } void Dijkstra(int s) { fill(dist, dist + n + 1, inf); dist[s] = 0; q.push({ 0, s }); while (!q.empty()) { node tmp = q.top(); q.pop(); int x = tmp.pos; if (visited[x])continue; visited[x] = 1; for (int i = head[x]; i; i = e[i].next) { int y = e[i].to; if (dist[y] > dist[x] + e[i].dis) { dist[y] = dist[x] + e[i].dis; q.push({ dist[y], y }); } } } } void FDijkstra(int s) { fill(dist2, dist2 + n + 1, inf); dist2[s] = 0; q2.push({ 0, s }); while (!q2.empty()) { node tmp = q2.top(); q2.pop(); int x = tmp.pos; if (visited2[x])continue; visited2[x] = 1; for (int i = head2[x]; i; i = e2[i].next) { int y = e2[i].to; if (dist2[y] > dist2[x] + e2[i].dis) { dist2[y] = dist2[x] + e2[i].dis; q2.push({ dist2[y], y }); } } } } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); addedge(a, b, c); addedge2(b, a, c); } Dijkstra(1); FDijkstra(1); long long answer = 0; for (int i = 2; i <= n; i++) answer += dist[i] + dist2[i]; printf("%lld", answer); }