题目描述
wlswls 正在玩一个寻宝游戏。
宝藏一共有 nn 种,都藏在一个 mm 行 mm 列的网格中。
每种宝藏都恰好有两个。
wlswls 只能沿着网格走(上下左右四个方向)。
他想依次获得 1\cdots n1⋯n 类宝藏,然后再以 n\cdots 1n⋯1 的顺序获得剩下的宝藏。
wlswls 可以从任意点出发。
当 wlswls 到达某个宝藏的位置时,他可以选择取或不取这个宝藏。
请问他最少要移动多少距离?
输入描述
第一行两个整数 n,mn,m。
接下来 nn 组,每组两行表示一类宝藏,每行两个整数 x,yx,y 表示一个宝藏的坐标。
1 \leq n, m \leq 1000001≤n,m≤100000
1 \leq x, y \leq m1≤x,y≤m
输出描述
一行一个整数表示答案。
样例输入 1
2 10
1 1
2 2
3 3
4 4
样例输出 1
10
思路:
从终点开始考虑。
设每一类的一个物品坐标为a[i],第二个物品坐标为b[i]。
则最后一步的结尾答案一定是cal(a[n],b[n])。cal()代表曼哈顿距离。
从后往前,每一步有两个决策,从第a[i - 1] 走到 a[i] ,从b[i] 走到 b[i - 1]或者从a[i - 1]走到b[i],从a[i]走到b[i - 1]。且最小值的决策就是全局最优决策,所以可以贪心的直接选过去。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
struct Node
{
ll x,y;
}a[maxn],b[maxn];
ll cal(Node a,Node b)
{
return abs(a.x - b.x) + abs(a.y - b.y);
}
int main()
{
int n,m;scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
scanf("%lld%lld%lld%lld",&a[i].x,&a[i].y,&b[i].x,&b[i].y);
}
ll ans = cal(a[n],b[n]);
for(int i = n;i >= 2;i--)
{
ans += min(cal(a[i],a[i - 1]) + cal(b[i],b[i - 1]),cal(a[i],b[i - 1]) + cal(b[i],a[i - 1]));
}
printf("%lld\n",ans);
return 0;
}