题意
坐标系上有\(n\)个点,每个点的级别为\(max(x,y)\),只有上一级的点全都走过了才能往下一级走,求走完所有点最小的长度。
思路
可发现每个级其实是一个倒L形,一个显然的结论:走完一个级要么从最左下角走到最右上角,反之。
因为如果从中间的一个点走到左边再走到右边,等价于从上一级走到当前级的最左边或最右边。或者是不按这两种方式走会使得长度不是最优秀的。
设\(f_{i,0/1}\)为走完第i级,当前是在最左边还是最右边。
代码
#include <cstdio>
#include <algorithm>
#define int long long
using namespace std;
struct node {
int x, y, c;
}p[200001];
int n, cnt;
int a[200001], f[200001][2], l[200001], r[200001];
bool operator < (node x, node y) {
if (x.c != y.c) return x.c < y.c;
if (x.x != y.x) return x.x < y.x;
return x.y > y.y;
}
int dis(int aa, int bb) {
return abs(p[aa].x - p[bb].x) + abs(p[aa].y - p[bb].y);
}
signed main() {
scanf("%lld", &n);
for (int i = 1; i <= n; i++)
scanf("%lld %lld", &p[i].x, &p[i].y), p[i].c = max(p[i].x, p[i].y);
sort(p + 1, p + n + 1);
for (int i = 1; i <= n; i++) {
if (p[i].c != p[i - 1].c) a[++cnt] = p[i].c, r[cnt] = i;
if (p[i].c != p[i + 1].c) l[cnt] = i;
}
for (int i = 1; i <= cnt; i++) {
f[i][0] = min(f[i - 1][0] + dis(l[i - 1], r[i]), f[i - 1][1] + dis(r[i - 1], r[i])) + dis(l[i], r[i]);//0左下, 1右上
f[i][1] = min(f[i - 1][0] + dis(l[i - 1], l[i]), f[i - 1][1] + dis(r[i - 1], l[i])) + dis(l[i], r[i]);
}
printf("%lld", min(f[cnt][0], f[cnt][1]));
}