题目地址:
https://www.luogu.com.cn/problem/P1342
题目背景:
在电视时代,没有多少人观看戏剧表演。Malidinesia古董喜剧演员意识到这一事实,他们想宣传剧院,尤其是古色古香的喜剧片。
题目描述:
他们已经打印了请帖和所有必要的信息和计划。许多学生被雇来分发这些请柬。每个学生志愿者被指定一个确切的公共汽车站,他或她将留在那里一整天,邀请人们参与。这里的公交系统是非常特殊的:共有
n
n
n个站点和
m
m
m个线路,所有的线路都是单向的,连接两个站点。公共汽车离开起始点,到达目的地之后又空车返回起始点。学生每天早上从总部所在的
1
1
1号站点出发,乘公交车到一个预定的站点邀请乘客。每个站点都被安排了一名学生。在一天结束的时候,所有的学生都回到总部。现在需要知道的是,学生所需的公交费用的总和最小是多少。
输入格式:
输入的第一行是两个整数,代表站点个数
n
n
n和线路条数
m
m
m。第
2
2
2到第
(
m
+
1
)
(m + 1)
(m+1)行,每行三个整数
u
,
v
,
w
u, v, w
u,v,w,代表存在一条从
u
u
u出发到达
v
v
v的线路,费用为
w
w
w。
输出格式:
输出一行一个整数,表示最小费用。
数据范围:
对于
100
%
100\%
100%的数据,保证:
1
≤
n
,
m
≤
1
0
6
1 \leq n, m \leq 10^6
1≤n,m≤106。
1
≤
u
,
v
≤
n
1 \leq u, v \leq n
1≤u,v≤n,
1
≤
w
≤
1
0
9
1 \leq w \leq 10^9
1≤w≤109。
从
1
1
1出发可以到达所有的站点。
即求 1 1 1为起点的单源最短路,为了求返回最短路,可以建立反向边再求一遍单源最短路。可以用两边Dijkstra算法来做。代码如下:
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
using ll = long long;
using PLI = pair<ll, int>;
const int N = 1e6 + 10;
int n, m;
int h[2][N], e[2][N], ne[2][N], w[2][N], idx[2];
bool vis[N];
ll dist[N];
priority_queue<PLI, vector<PLI>, greater<>> heap;
#define add(a, b, c, i) \
e[i][idx[i]] = b, ne[i][idx[i]] = h[i][a], w[i][idx[i]] = c, \
h[i][a] = idx[i]++
ll dijkstra(int i) {
memset(dist, 0x3f, sizeof dist);
memset(vis, 0, sizeof vis);
heap.push({0, 1});
while (heap.size()) {
auto t = heap.top(); heap.pop();
ll d = t.first;
int u = t.second;
if (vis[u]) continue;
vis[u] = true;
dist[u] = d;
for (int j = h[i][u]; ~j; j = ne[i][j]) {
int v = e[i][j];
if (!vis[v] && dist[v] > d + w[i][j]) {
dist[v] = d + w[i][j];
heap.push({dist[v], v});
}
}
}
ll res = 0;
for (int i = 1; i <= n; i++) res += dist[i];
return res;
}
int main() {
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while (m--) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c, 0), add(b, a, c, 1);
}
printf("%lld\n", dijkstra(0) + dijkstra(1));
}
时间复杂度 O ( m log n ) O(m\log n) O(mlogn),空间 O ( n + m ) O(n+m) O(n+m)。