D66 最短路+建反图 Dijkstra 算法 P1629 邮递员送信
D66 最短路+建反图 Dijkstra 算法 P1629 邮递员送信_哔哩哔哩_bilibili
有一个邮递员要送东西,邮局在节点 1。他总共要送 n−1 样东西,其目的地分别是节点 2 到节点 n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n−1 样东西并且最终回到邮局最少需要的时间。输入保证任意两点都能互相到达。
思路
注意“道路都是单行的”,送东西是一点到多点,跑一遍单源最短路,求和。
注意“保证任意两点都能互相到达”,返回时是多点到一点,只要再建个反图,就能变成一点到多点,再跑一遍单源最短路,求和。

小技巧:建正图的同时,倍增各点建反图。即 $1→1+n,2→2+n,...$。
相关板子:
D02【模板】最短路 Dijkstra 算法 P4779 单源最短路径 - 董晓 - 博客园
// 最短路+建反图 Dijkstra 算法 O(mlogn) #include<bits/stdc++.h> #define pli pair<long long,int> using namespace std; const int N=2005; int n,m; vector<pli> e[N]; long long d[N]; void dijkstra(int s){ memset(d,0x3f,sizeof d); d[s]=0; priority_queue<pli,vector<pli>,greater<pli> > q; //小根堆 q.emplace(0,s); while(q.size()){ auto [dd,u]=q.top(); q.pop(); if(dd>d[u]) continue; //这个u不是第一次出队,不拓展 for(auto [w,v]:e[u]){ if(d[v]>d[u]+w) q.emplace(d[v]=d[u]+w,v); } } } int main(){ cin>>n>>m; for(int i=0,u,v,w; i<m; i++){ cin>>u>>v>>w; e[u].emplace_back(w,v); //建图 e[v+n].emplace_back(w,u+n); //建反图 } long long ans=0; dijkstra(1); for(int i=2; i<=n; ++i) ans+=d[i]; //1到各点的最短路之和 dijkstra(1+n); for(int i=2+n; i<=n<<1; ++i) ans+=d[i]; //各点到1的最短路之和 printf("%lld",ans); }
浙公网安备 33010602011771号