「AMPPZ2014」The Captain
首先我们有一个朴素的最短路做法,对于 \(u(x_u, y_u)\) 和 \(v(x_v, y_v)\) 连一条边权为 \(\min(|x_u - x_v|, |y_u - y_v|)\) 的边,进一步发现在最短路的条件下可以转化为分别连边权为 \(|x_u - x_v|\) 和 \(|y_u - y_v|\) 的边。
考虑优化边数,因为我没想到只需连在横坐标上和纵坐标上最近的四点即可,所以我考虑构造一个建图方案使得所有边能不漏地对应上去。
考虑到走边可以看作先选定一个方向,在该方向上左右移动,花费移动距离的代价,再走到当前轴上对应的随便一个点,所以有对于连边 \(u(x_u, y_u)\), \(v(x_v, y_v)\) 在坐标轴上对应为下图(红边代表原本连边,蓝边代表改后连边)

然后发现对于所有从 \(u\) 连出的边共享一条边权为 \(0\) 的边,所有从 \(v\) 连入的边共享一条边权为 \(0\) 的边,然后在 \(x\) 轴和 \(y\) 轴上的边共享一条链,如下图

最后对 \(x\) 轴和 \(y\) 轴上的边离散化一下就得到了总边数 \(O(N)\) 的图,并且完美包含原图所有路径。
/*
address:https://qoj.ac/problem/11560
AC 2026/7/22 14:53
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5;
const LL INF = 1e18;
struct edge { int to, w; };
vector<edge>G[N];
int n;
int x[N], y[N];
int disc1[N], m1, disc2[N], m2;
inline void build_graph() {
for (int i = 1;i <= n;++i) {
G[i].push_back({ x[i] + n, 0 });
G[x[i] + n].push_back({ i, 0 });
G[i].push_back({ y[i] + m1 + n, 0 });
G[y[i] + m1 + n].push_back({ i, 0 });
}
for (int i = 1;i < m1;++i) {
G[i + n].push_back({ i + 1 + n, disc1[i + 1] - disc1[i] });
G[i + 1 + n].push_back({ i + n, disc1[i + 1] - disc1[i] });
}
for (int i = 1;i < m2;++i) {
G[i + n + m1].push_back({ i + 1 + n + m1, disc2[i + 1] - disc2[i] });
G[i + 1 + n + m1].push_back({ i + n + m1, disc2[i + 1] - disc2[i] });
}
}
struct node {
int u;
LL dist;
bool operator < (const node& o)const { return dist > o.dist; }
};
priority_queue<node>q;
LL dis[N];
bool vis[N];
inline void dijkstra() {
for (int i = 1;i <= n + m1 + m2;++i) dis[i] = INF, vis[i] = false;
dis[1] = 0;
q.push({ 1, 0 });
while (!q.empty()) {
int u = q.top().u;
q.pop();
if (vis[u]) continue;
vis[u] = true;
for (auto [v, w] : G[u])
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
q.push({ v, dis[v] });
}
}
}
inline void init(int* disc, int& m, int* x) {
for (int i = 1;i <= n;++i) disc[++m] = x[i];
sort(disc + 1, disc + m + 1);
m = unique(disc + 1, disc + m + 1) - disc - 1;
for (int i = 1;i <= n;++i) x[i] = lower_bound(disc + 1, disc + m + 1, x[i]) - disc;
}
int main() {
scanf("%d", &n);
for (int i = 1;i <= n;++i) scanf("%d%d", &x[i], &y[i]);
init(disc1, m1, x), init(disc2, m2, y);
build_graph();
dijkstra();
printf("%lld", dis[n]);
return 0;
}

浙公网安备 33010602011771号