一、题目
1、题目描述
2、输入输出
2.1输入
2.2输出
3、原题链接
二、解题报告
1、思路分析
题意看似很简单,就是问我们两个人分别处于1, p两个点上,二者同时出发,相遇时二者所用路径之和的最小值
不难想到求1为源点的最短路,但是我们发现将路径从相遇点分为两段的话,一段是从1出发,一段从另一边出发,原始的堆优化dijkstra似乎不能用了
类似网络流对于图的处理,我们也将每条边建一条反向边
这样以来,图中的边无非两种状态:0(正向),1(反向)
那么我们最小方案中两人的路径可以看作从1出发的人先走若干0边,再走若干1边
也就是说,我们从1出发,如果先前走的都是0边,我们下一条边可以0可以1
但是一旦走了一条1边,就只能走1边了
按照上述原则,我们建图,跑dijkstra即可,详细实现看代码
2、复杂度
时间复杂度: O(N + MlogM)空间复杂度:O(N + M)
3、代码详解
状态不太好,直接无脑define int long long 了
#include <bits/stdc++.h>
using i64 = long long;
using i128 = __int128;
#define int long long
using PII = std::pair<int, int>;
using PIII = std::pair<int, PII>;
const int inf = 1e18 + 7, P = 1e9 + 7;
struct edge {
int v, w, nxt;
bool inv;
};
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<int> head(n, -1);
std::vector<edge> adj;
adj.reserve(m << 1);
auto addedge = [&](int u, int v, int w, bool inv) -> void {
adj.push_back( { v, w, head[u], inv } ), head[u] = adj.size() - 1;
};
for (int i = 0, u, v, w; i < m; ++ i) {
std::cin >> u >> v >> w;
-- u, -- v;
addedge(u, v, w, 0);
addedge(v, u, w, 1);
}
std::priority_queue<PIII, std::vector<PIII>, std::greater<PIII>> pq;
std::vector<std::array<int, 2>> dst(n, { inf, inf } );
pq.push( { 0, { 0, 1 } } );
pq.push( { 0, { 0, 0 } } );
while (pq.size()) {
auto [d, p] = pq.top();
auto [u, u_inv] = p;
pq.pop();
if (d > dst[u][u_inv]) continue;
for (int i = head[u]; ~i; i = adj[i].nxt) {
int v = adj[i].v, w = adj[i].w;
bool e_inv = adj[i].inv;
int newd = d + w;
if ((e_inv == 1 || u_inv == 0) && newd < dst[v][e_inv]) {
dst[v][e_inv] = newd;
pq.push( { newd, { v, e_inv } } );
}
}
}
for (int i = 1; i < n; ++ i) {
int out = std::min(dst[i][0], dst[i][1]);
std::cout << (out < inf ? out : -1) << " \n"[i == n - 1];
}
}
#undef int
int main(int argc, char** argv) {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int _ = 1;
// std::cin >> _;
while (_ --)
solve();
return 0;
}