阅读 82

CF1066F 二维移动

1 CF1066F 二维移动

  • 题目链接:

2 题目描述

时间限制 \(4s\) | 空间限制 \(256M\)

Maksim walks on a Cartesian plane. Initially, he stands at the point \((0,0)\) and in one move he can go to any of four adjacent points (left, right, up, down). For example, if Maksim is currently at the point \((0,0)\), he can go to any of the following points in one move:

  • \((1,0);\)
  • \((0,1);\)
  • \((?1,0);\)
  • \((0,?1).\)

There are also \(??\) distinct key points at this plane. The ??-th point is \(??_??=(??_??,??_??)\). It is guaranteed that \(0≤??_??\) and \(0≤??_??\) and there is no key point \((0,0)\).

Let the first level points be such points that \(??????(??_??,??_??)=1\), the second level points be such points that \(??????(??_??,??_??)=2\) and so on. Maksim wants to visit all the key points. But he shouldn‘t visit points of level \(??+1\) if he does not visit all the points of level \(??\). He starts visiting the points from the minimum level of point from the given set.

The distance between two points \((??_1,??_1)\) and \((??_2,??_2)\) is \(|??_1???_2|+|??_1???_2|\) where \(|??|\) is the absolute value of \(??\).

Maksim wants to visit all the key points in such a way that the total distance he walks will be minimum possible. Your task is to find this distance.

数据范围:\(1≤??≤2\times 10^5; 0≤??_??,??_??≤10^9\)

3 题解

性质:我们移动到某一层时,我们的最优策略是从前一层的两个端点到这一层的两个端点(端点意为满足 \(max(x_i, y_i) = m_i\) 的点中 \(x_i\) 最小的点和 \(y_i\) 最小的点,有可能是同一个点)。这是因为,我们如果在非端点之间转移,那么我们在遍历这一层所有端点时会重复一部分路径。这部分路径长度一定不小于端点之间连接时的路径长度,所以最优策略是在端点之间转移。

接下来我们可以将把每一层的节点全部遍历完所需要走的距离都预先计算出来,然后利用 \(dp\) 计算最终需要走过的最短路径。此时我们设 \(dp_{i, 0/1}\) 表示走完第 \(i\) 层且第 \(i-1\) 层是从第 \(i\) 层的左端点(\(x_i\) 最小的点)或者右端点(\(y_i\) 最小的点)抵达第 \(i\) 层的时我们的最短路径,我们设第 \(i\) 层的左端点坐标为 \((posx_{i, 0}, posy_{i, 0})\),右端点坐标为 \((posx_{i, 1}, posy_{i, 1})\)。此时转移就是:

\[dp_{i, 0} = min(dp_{i-1, 0} + |posx_{i, 0} - posx_{i-1, 0}| + |posy_{i, 0} - posy_{i-1, 0}|, dp_{i-1, 1} + |posx_{i, 0} - posx_{i-1, 1}| + |posy_{i, 0} - posy_{i-1, 1}|) \]

\[dp_{i, 1} = min(dp_{i-1, 0} + |posx_{i, 1} - posx_{i-1, 0}| + |posy_{i, 1} - posy_{i-1, 0}|, dp_{i-1, 1} + |posx_{i, 1} - posx_{i-1, 1}| + |posy_{i, 1} - posy_{i-1, 1}|) \]

最后,我们的答案就是 \(min(dp_{n, 0}, dp_{n, 1})\)

4 代码(空格警告):

#include 
#include 
using namespace std;
const int N = 2e5+10;
#define int long long
int n, cnt;
struct point
{
    int m, x, y;
}a[N];
int c[N], dp[N][3];
pair  pos[N][3];
bool cmp(point x, point y)
{
    if (x.m == y.m)
    {
        if (x.x == y.x) return x.y > y.y;
        return x.x < y.x;
    }
    return x.m < y.m;
}
int dis(int x, int y, int X, int Y)
{
    return abs(x - X) + abs(y - Y);
}
signed main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i].x >> a[i].y;
        a[i].m = max(a[i].x, a[i].y);        
    }
    sort(a+1, a+n+1, cmp);
    pos[0][0].first = pos[0][0].second = 0;
    for (int i = 1; i <= n; i++)
    {
        if (a[i].m != a[i-1].m)
        {
            pos[cnt][1].first = a[i-1].x, pos[cnt][1].second = a[i-1].y;
            cnt++;
            pos[cnt][0].first = a[i].x, pos[cnt][0].second = a[i].y;
        }
        else c[cnt] += dis(a[i].x, a[i].y, a[i-1].x, a[i-1].y);
    }
    pos[cnt][1].first = a[n].x, pos[cnt][1].second = a[n].y;
    for (int i = 1; i <= cnt; i++)
    {
        dp[i][0] = min(dp[i-1][0] + dis(pos[i-1][1].first, pos[i-1][1].second, pos[i][0].first, pos[i][0].second), dp[i-1][1] + dis(pos[i-1][0].first, pos[i-1][0].second, pos[i][0].first, pos[i][0].second)) + c[i];
        dp[i][1] = min(dp[i-1][0] + dis(pos[i-1][1].first, pos[i-1][1].second, pos[i][1].first, pos[i][1].second), dp[i-1][1] + dis(pos[i-1][0].first, pos[i-1][0].second, pos[i][1].first, pos[i][1].second)) + c[i];
    }
    cout << min(dp[cnt][0], dp[cnt][1]);
    return 0;
}

欢迎关注我的公众号:智子笔记

原文:https://www.cnblogs.com/david24/p/14655023.html

文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐