一、题目
1、题目描述
2、输入输出
2.1输入
2.2输出
3、原题链接
1725M - Moving Both Hands
二、解题报告
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 intint 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;
}