题目描述
有一个邮递员要送东西,邮局在节点 1 1 1。他总共要送 n − 1 n-1 n−1 样东西,其目的地分别是节点 2 2 2 到节点 n n n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m m m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n − 1 n-1 n−1 样东西并且最终回到邮局最少需要的时间。
输入格式
第一行包括两个整数, n n n 和 m m m,表示城市的节点数量和道路数量。
第二行到第 ( m + 1 ) (m+1) (m+1) 行,每行三个整数, u , v , w u,v,w u,v,w,表示从 u u u 到 v v v 有一条通过时间为 w w w 的道路。
输出格式
输出仅一行,包含一个整数,为最少需要的时间。
样例 #1
样例输入 #1
5 10
2 3 5
1 5 5
3 5 6
1 2 8
1 3 8
5 3 4
4 1 8
4 5 3
3 5 6
5 4 2
样例输出 #1
83
提示
对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 200 1 \leq n \leq 200 1≤n≤200。
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 3 1 \leq n \leq 10^3 1≤n≤103, 1 ≤ m ≤ 1 0 5 1 \leq m \leq 10^5 1≤m≤105, 1 ≤ u , v ≤ n 1\leq u,v \leq n 1≤u,v≤n, 1 ≤ w ≤ 1 0 4 1 \leq w \leq 10^4 1≤w≤104,输入保证任意两点都能互相到达。
- 从邮局出发到各个邮寄点肯定是单源最短路问题,即用dijkstra,考虑到本题数据量,存图需要用带权的链式前向星,并且还要再需堆优化一下;而折返回来时就属于多源单终点问题,但仍可以套dijkstra做,但需要再建一个存反向边的图。
C++代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int, int> PII; //first:与源点距离 second:结点编号
const int N = 1e5 + 10;
/**
* @brief 两遍dijkstra,从邮局过去一遍是单源多点最短路,所以可按照原本建边的顺序直接dijkstra
* 回来的时候是多源单终点问题,但也可以转换为为dijkstra做,只用反向再建一下边
* <-------反向建边的时候注意设置一个+n的偏移量来防止建边冲突-------->
*/
int e[2 * N], ne[2 * N], h[2 * N], w[2 * N];
int dist[2 * N];
bool st[2 * N];
int n, m, idx = 0;
int res = 0; //要走的所有路程
priority_queue<PII, vector<PII>, greater<PII>> heap; //按照源点距离排的小根堆
void add(int a, int b, int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
void dijkstra(int s){
memset(dist, INF, sizeof dist);
dist[s] = 0;
heap.push({0, s});
while(heap.size()){
PII t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver];i != -1;i = ne[i]){
int j = e[i];
if(w[i] + distance < dist[j]){
dist[j] = w[i] + distance;
heap.push({dist[j], j});
}
}
}
}
int main(){
scanf("%d %d", &n, &m);
memset(h, -1, sizeof h);
while(m --){
int u, v, z;
scanf("%d %d %d", &u, &v, &z);
add(u, v, z);
add(v + n, u + n, z); //反向再建一遍图,+ n对每个点做一个偏移
}
dijkstra(1);
for(int i = 1;i <= n;i ++) res += dist[i];
dijkstra(1 + n);
for(int i = 1 + n;i <= n + n;i ++) res += dist[i];
cout << res << endl;
return 0;
}