[某人的题解]徒步旅行(travel)

题目描述

小 A 决定开始一场奇妙的徒步旅行,旅行地图可以看成是一个平面直角坐标系,小 A 从家 O ( 0 , 0 ) O(0, 0) O(0,0)出发,每一步移动只能由他此时所在的位置 ( x , y ) (x,y) (x,y)走到以下四个坐标之一: ( x − 1 , y ) , ( x , y − 1 ) , ( x + 1 , y ) , ( x , y + 1 ) (x-1,y),(x,y-1),(x+1,y),(x,y+1) (x1,y),(x,y1),(x+1,y),(x,y+1)

现在有 n n n个旅游景点,第 i i i个旅游景点位置为(xi ,yi)。

由于世界如此之大,整个旅行地图被分成了多个不同的气候区,某个景点(xi ,yi)的气候区Ci=max(xi ,yi) 。小 A 想要更好的了解这个世界使得他这次徒步旅行更有意义,所以他想要去气候区 旅行当且仅当访问完气候区为 的所有旅游景点。当他访问完所有的景点时,他会回到家里。

输入格式

小 A 想让你帮他设计出一条旅游路线使得他移动的步数最少,因为徒步旅行还是比较累的……
输入格式
第一行输入一个整数n,表示旅游景点数量。
接下来n行,每行一个整数对(xi ,yi)代表第 个景区的位置。

输出格式

仅一行,表示小 A 完成旅行所需移动的最少步数。

样例

样例输入1

8
2 2
1 4
2 3
3 1
3 4
1 1
4 3
1 2

样例输出1

20

样例输入2

5
2 1
1 0
2 0
3 2
0 3

样例输出2

12

在这里插入图片描述

分析

首先看到这一道题,一定会想到使用搜索(他把方向都告诉你了)。
但我看了一眼数据—— 1 0 9 10^9 109。(我TM直接放弃
所以说搜索是肯定会超时的。但终究有点分。
对于每一个气候,可以发现它的起点和终点最有的取法一定是两个端点。
在最优解中,只需要走到两个端点,就可以遍历玩这一气候区的所有点。


然后……
先把输入的 x , y x,y x,y按气候区的从小到大排序,即:

bool cmp(Node x, Node y) {
    
    
	return x.Map_C != y.Map_C ? x.Map_C < y.Map_C : (x.Map_X != y.Map_X ? x.Map_X < y.Map_X : x.Map_Y < y.Map_Y); 
}

我们用两个dp来存储,一个存贮最左端点,一个存储最右端点。
所以
d p 1 [ i ] = m i n ( d p 1 [ i − 1 ] + c a l c ( l [ i − 1 ] , r [ i ] ) , d p 2 [ i − 1 ] + c a l c ( r [ i − 1 ] , r [ i ] ) ) + c a l c ( r [ i ] , l [ i ] ) ; dp1[i] = min(dp1[i - 1] + calc(l[i - 1], r[i]), dp2[i - 1] + calc(r[i - 1], r[i])) + calc(r[i], l[i]); dp1[i]=min(dp1[i1]+calc(l[i1],r[i]),dp2[i1]+calc(r[i1],r[i]))+calc(r[i],l[i]);
d p 2 [ i ] = m i n ( d p 1 [ i − 1 ] + c a l c ( l [ i − 1 ] , l [ i ] ) , d p 2 [ i − 1 ] + c a l c ( r [ i − 1 ] , l [ i ] ) ) + c a l c ( l [ i ] , r [ i ] ) ; dp2[i] = min(dp1[i - 1] + calc(l[i - 1], l[i]), dp2[i - 1] + calc(r[i - 1], l[i])) + calc(l[i], r[i]); dp2[i]=min(dp1[i1]+calc(l[i1],l[i]),dp2[i1]+calc(r[i1],l[i]))+calc(l[i],r[i]);
l [ i ] l[i] l[i]用于记录最左端点的排序后顺序, r [ i ] r[i] r[i]用于记录最右端点的排序后顺序,calc函数是用来计算两点间距离的,不难想到:

long long calc(long long x, long long y) {
    
    
	return abs(a[x].Map_X - a[y].Map_X) + abs(a[x].Map_Y - a[y].Map_Y);
}

(注:记得将气候区离散化,否则会超时)

代码实现

综上所述,代码就出来了

#include <map>
#include <set>
#include <cstdio>
#include <algorithm>
using namespace std;
#define ll long long
const ll MAXN = 3e5 + 5;
struct Node {
    
    
	ll Map_X, Map_Y, Map_C;
};
set<ll> st;
map<ll, ll> mpl;
map<ll, ll> mpr;
map<ll, ll> id1;
map<ll, ll> id2;
map<ll, bool> mpX;
map<ll, bool> mpY;
Node a[MAXN];
ll dp1[MAXN], dp2[MAXN];
ll l[MAXN], r[MAXN];
ll n;
bool cmp(Node x, Node y) {
    
    
	return x.Map_C != y.Map_C ? x.Map_C < y.Map_C : (x.Map_X != y.Map_X ? x.Map_X < y.Map_X : x.Map_Y < y.Map_Y); 
}
ll calc(ll x, ll y) {
    
    
	return abs(a[x].Map_X - a[y].Map_X) + abs(a[x].Map_Y - a[y].Map_Y);
}
void Read() {
    
    
	scanf("%lld", &n);
	mpX[0] = mpY[0] = 1;
	for(ll i = 1; i <= n; i++) {
    
    
		scanf("%lld %lld", &a[i].Map_X, &a[i].Map_Y);
		a[i].Map_C = max(a[i].Map_X, a[i].Map_Y);
		st.insert(a[i].Map_C);
	}
	for(set<ll>::iterator it = st.begin(); it != st.end(); it++) {
    
    
		mpl[*it] = 0x7fffffff;
	}
	sort(a + 1, a + 1 + n, cmp);
	for(ll i = 1; i <= n; i++) {
    
    
		if(min(a[i].Map_X, a[i].Map_Y) <= mpl[a[i].Map_C]) {
    
    
			mpl[a[i].Map_C] = min(mpl[a[i].Map_C], min(a[i].Map_X, a[i].Map_Y));
			id2[a[i].Map_C] = i;
		}
		if(min(a[i].Map_X, a[i].Map_Y) >= mpr[a[i].Map_C]) {
    
    
			mpr[a[i].Map_C] = max(mpr[a[i].Map_C], min(a[i].Map_X, a[i].Map_Y));
			id1[a[i].Map_C] = i;
		}
	}
	int p = 0;
	for(set<ll>::iterator it = st.begin(); it != st.end(); it++) {
    
    
		l[++p] = id2[*it];
		r[p] = id1[*it];
	}
	for(ll i = 1; i <= p; i++) {
    
    
        dp1[i] = min(dp1[i - 1] + calc(l[i - 1], r[i]), dp2[i - 1] + calc(r[i - 1], r[i])) + calc(r[i], l[i]);
        dp2[i] = min(dp1[i - 1] + calc(l[i - 1], l[i]), dp2[i - 1] + calc(r[i - 1], l[i])) + calc(l[i], r[i]);
	}
	printf("%lld", min(dp1[p] + calc(l[p], 0), dp2[p] + calc(r[p], 0)));
}
int main() {
    
    
	Read();
	return 0;
}

可能有亿点点麻烦,真就亿点点呗。(小声)

猜你喜欢

转载自blog.csdn.net/Face_the_Blast/article/details/108883577
今日推荐