D66 最短路+建反图 Dijkstra 算法 P1629 邮递员送信

D66 最短路+建反图 Dijkstra 算法 P1629 邮递员送信_哔哩哔哩_bilibili

 

P1629 邮递员送信 - 洛谷

有一个邮递员要送东西,邮局在节点 1。他总共要送 n−1 样东西,其目的地分别是节点 2 到节点 n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n−1 样东西并且最终回到邮局最少需要的时间。输入保证任意两点都能互相到达。

思路

注意“道路都是单行的”,送东西是一点到多点,跑一遍单源最短路,求和。

注意“保证任意两点都能互相到达”,返回时是多点到一点,只要再建个反图,就能变成一点到多点,再跑一遍单源最短路,求和。

                                      image

小技巧:建正图的同时,倍增各点建反图。即 $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);
}

 

posted @ 2026-02-12 17:52  董晓  阅读(140)  评论(0)    收藏  举报