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})\)。此时转移就是:
最后,我们的答案就是 \(min(dp_{n, 0}, dp_{n, 1})\)。
4 代码(空格警告):
#include <iostream>
#include <algorithm>
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 <int, int> 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;
}