[Wannafly冬令营2018Day4]夺宝奇兵(贪心)

题目描述

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;
}

发布了594 篇原创文章 · 获赞 16 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/103529221