20250827 XYD 003 T3
题意
求 \(1\) 到 \(n\) 边权极差最大的最短路
思路
Pre(最短路图)
求\(s \to t\) 的最短路图:正反跑最短路,然后对每条边判断是否满足 $dist_s[u] + 1 == dist_s[0][v] $ && $ dist_s[u] + 1 + dist_t[v] == dist_s[t]$,满足就建边。
考虑暴力。
极差肯定是两条边,所以可以枚举两条边,然后判断两条边是否在 $1 $ 到 \(n\) 的最短路上,如果在,就把答案和他们的差取 \(\max\)。\(O(M^2)\)。
考虑优化
由于要求是在最短路上,所以可以先求出 \(1\) 到 \(n\) 的最短路图。考虑枚举最大边,再找最小边。若当前枚举最大边为 \((u, v, w)\) 那么就是要找到在最短路图上,\(s \to u\) 的所有路径上的最小边权,和 $ \to t$ 的所有路径上的最小边权。由于最短路图是 DAG,所以正反两边拓扑排序找最小边权即可。由于要找到整个路径,所以在拓扑排序的同时记录最小边权是从哪里来的即可。
如果不想跑两边拓扑排序,可按如下思路:由于最短路图是 DAG,所以可以钦定当前边为最大边或最小边,若请钦定为最大边,则要求 \(s \to u\) 的所有路径上的最小边权,反之同理,同时也要记录是从哪里来。
Code
跑两遍
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, M = 2e5 + 5, INF = 1e9, END = 1e5 + 1;
struct Node {
int u, dis;
};
struct Edge {
int u, v, w;
};
struct To {
int v, w;
};
struct Cmp {
bool operator () (const Node &a, const Node &b) const {
return a.dis > b.dis;
}
};
int n, m, ans;
int dist[2][N], in[2][N], flag[M], mn[2][N], pre[2][N];
//mn 为最小边权 pre 记录从最小边权哪里来
Edge e[M]; // 边集
vector<To> g[N];
queue<int> q; // 拓扑用
deque<int> dq; // 求答案用
priority_queue<Node, vector<Node>, Cmp> pq;
void Dijkstra(int id, int s) { // 不要学我(不读题导致的) 用 BFS 即可
for (int i = 1; i <= n; i++) {
dist[id][i] = INF;
}
pq.push({s, 0});
while (!pq.empty()) {
int u = pq.top().u;
int dis = pq.top().dis;
pq.pop();
if (dist[id][u] != INF) {
continue;
}
dist[id][u] = dis;
for (To t : g[u]) {
int v = t.v, w = t.w;
pq.push({v, dis + 1});
}
}
return ;
}
void Build() {//建最短路图
for (int i = 1; i <= n; i++) {
g[i].clear();
}
for (int i = 1; i <= m; i++) {
int &u = e[i].u, &v = e[i].v, &w = e[i].w;
if (dist[0][u] > dist[0][v]) {//将边的方向改为正向
swap(u, v);
}
if (dist[0][u] + 1 == dist[0][v] && dist[0][u] + 1 + dist[1][v] == dist[0][n]) {
// cout << u << ' ' << v << ' ' << w << '\n';
flag[i] = 1;//标记为最短路图上的边
in[0][v]++, in[1][u]++;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
}
return ;
}
void Kahn(int id) {
for (int i = 1; i <= n; i++) {
mn[id][i] = INF;
pre[id][i] = END;
if (!in[id][i]) {
q.push(i);
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (To t : g[u]) {
int v = t.v, w = t.w;
if (in[id][v] <= 0) {//由于我建的是无向图,所以可能往前走
continue;
}
int res = min(w, mn[id][u]);
if (mn[id][v] > res) {
mn[id][v] = res;
pre[id][v] = u;
}
if (!--in[id][v]) {
q.push(v);
}
}
}
return ;
}
int F(int i) {
return e[i].w - min({e[i].w, mn[0][e[i].u], mn[1][e[i].v]});
}
void FindPath(int f, int u) {//找路径
for (; u != END; u = pre[f][u]) {
f == 0 ? dq.push_front(u) : dq.push_back(u);
}
return ;
}
int main() {
cin >> n >> m;
for (int i = 1, u, v, w; i <= m; i++) {
cin >> u >> v >> w;
e[i] = {u, v, w};
g[u].push_back({v, w});
g[v].push_back({u, w});
}
Dijkstra(0, 1);
Dijkstra(1, n);
Build();
Kahn(0), Kahn(1);
for (int i = 1; i <= m; i++) {
if (flag[i] && F(ans) <= F(i)) {
ans = i;
}
}
FindPath(0, e[ans].u);
FindPath(1, e[ans].v);
cout << (int)dq.size() - 1 << '\n';
for (int x : dq) {
cout << x << ' ';
}
return 0;
}
跑一遍
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5, M = 2e5 + 5, INF = 1e9, END = 1e5 + 1;
struct Node {
int u, dis;
};
struct Edge {
int u, v, w;
};
struct To {
int v, w, id;
};
struct Cmp {
bool operator () (const Node &a, const Node &b) const {
return a.dis > b.dis;
}
};
int n, m, ans;
int dist[2][N], in[N], flag[M], mn[N], mx[N], pre[N][2];
Edge e[M];
vector<To> g[N];
queue<int> q;
deque<int> dq;
priority_queue<Node, vector<Node>, Cmp> pq;
void Dijkstra(int id, int s) {
for (int i = 1; i <= n; i++) {
dist[id][i] = INF;
}
pq.push({s, 0});
while (!pq.empty()) {
int u = pq.top().u;
int dis = pq.top().dis;
pq.pop();
if (dist[id][u] != INF) {
continue;
}
dist[id][u] = dis;
for (To t : g[u]) {
int v = t.v, w = t.w;
pq.push({v, dis + 1});
}
}
return ;
}
void Build() {
for (int i = 1; i <= n; i++) {
g[i].clear();
}
for (int i = 1; i <= m; i++) {
int &u = e[i].u, &v = e[i].v, &w = e[i].w;
if (dist[0][u] > dist[0][v]) {
swap(u, v);
}
if (dist[0][u] + 1 == dist[0][v] && dist[0][u] + 1 + dist[1][v] == dist[0][n]) {
flag[i] = 1;
in[v]++;
g[u].push_back({v, w, i});
}
}
return ;
}
int F(int i) {
return max(abs(mx[e[i].u] - e[i].w), abs(e[i].w - mn[e[i].u]));
}
void Kahn() {
for (int i = 1; i <= n; i++) {
mn[i] = INF;
mx[i] = -INF;
pre[i][0] = pre[i][1] = END;
if (!in[i]) {
q.push(i);
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (To t : g[u]) {
int v = t.v, w = t.w, id = t.id;
if (F(ans) <= F(id)) {
ans = id;
}
int resmn = min(w, mn[u]);
int resmx = max(w, mx[u]);
if (mn[v] > resmn) {
mn[v] = resmn;
pre[v][0] = u;
}
if (mx[v] < resmx) {
mx[v] = resmx;
pre[v][1] = u;
}
if (!--in[v]) {
q.push(v);
}
}
}
return ;
}
inline void FindPath(int f, int u) {
for (; u != END; u = pre[u][f]) {
dq.push_front(u);
}
return ;
}
inline void FindPath2(int u) {
dq.push_back(u);
if (u == n) {
return ;
}
FindPath2(g[u][0].v);
return ;
}
main() {
cin >> n >> m;
for (int i = 1, u, v, w; i <= m; i++) {
cin >> u >> v >> w;
e[i] = {u, v, w};
g[u].push_back({v, w});
g[v].push_back({u, w});
}
Dijkstra(0, 1);
Dijkstra(1, n);
Build();
Kahn();
FindPath(mx[e[ans].u] - e[ans].w > e[ans].w - mn[e[ans].u], e[ans].u);//根据情况看走大走小
FindPath2(e[ans].v);
cout << (int)dq.size() - 1 << '\n';
for (int x : dq) {
cout << x << ' ';
}
return 0;
}

浙公网安备 33010602011771号