【动态规划 贪心】CF1066F Yet another 2D Walking

题意

坐标系上有\(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]));
}
上一篇:简单的Word操作对象


下一篇:项目要实现多数据源动态切换,咋搞?