codeJan与旅行

本文介绍了一个旅行路径规划问题,即给定多个城市位置和旅行者起始位置,如何计算旅行者游览特定数量城市的最短行走距离。文章通过具体示例展示了算法实现过程,并提供了源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述 

codeJan 非常喜欢旅行。现在有 n 个城市排在一条线上,并且 codeJan 的位置不和任何一个城市的位置重叠。
codeJan 想要游览 m 个城市,同时因为时间是不断变化的,游览一个城市多次也是允许的,但是不能永远待在一个城市,否则那样太无聊了。给出这些城市的位置,codeJan 想要知道游览 m 个城市至少需要走多少米?

输入描述:

第一行是一个T≤20代表测试组数。
每组第一行是三个正整数n,m,p,分别代表城市数量、codeJan想要浏览的城市数量和codeJan当前的位置(单位为米)。
第二行包含n个正整数pos[i]表示第i个城市的位置,单位为米。
输入保证pos[i]<pos[i+1](i∈[1,n−1]),并且p ≠ pos[i](i∈[1,n])。

输出描述:

对于每组输入数据输出一个正整数表示 codeJan 至少需要走的距离。
示例1

输入

3 
2 2 2 
1 3 
2 2 1 
2 3 
4 3 4 
1 3 5 6

输出

3
2
3

说明

对于第一个样例的坐标最优移动顺序可以是:2→3→1,移动距离一共是3。
对于第二个样例的坐标最优移动顺序可以是:1→2→3,移动距离一共是2。
对于第三个样例的坐标最优移动顺序可以是:4→5→6→5,移动距离一共是3。

备注:

2≤n≤105,1≤m≤10,1≤p,pos[i]≤109

解题思路:先找出当前点的左右两个城市,已知最后状态必然要么是恰好走到一个点要么就是在两个点之间来回走,所以枚举在那两个点之间来回即可

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <string>  
#include <algorithm>  
#include <cmath>  
#include <map>  
#include <set>  
#include <stack>  
#include <queue>  
#include <vector>  
#include <bitset>  
#include <functional>  

using namespace std;

#define LL long long  
const LL INF = 0x3f3f3f3f3f3f3f3f;

LL x[100009], p;
int n, m;

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d%lld", &n, &m, &p);
		for (int i = 1; i <= n; i++) scanf("%lld", &x[i]);
		int k = upper_bound(x + 1, x + 1 + n, p) - x;
		LL ans = INF, ans1 = 0, ans2 = 0;
		int id1 = -1, id2 = -1;
		if (k == n + 1) ans1 += p - x[n], id1 = n;
		else if (k == 1) ans2 += x[1] - p, id2 = 1;
		else
		{
			ans2 = x[k] - p, id2 = k;
			id1 = k - 1, ans1 = p - x[k - 1];
		}
		if (id1 != -1)
		{
			for (int i = 1; i <= id1; i++)
			{
				if (id1 - i + 1 > m || i == n) continue;
				LL dis = x[id1] - x[i];
				int tmp = id1 - i + 1;
				dis += 1LL * (x[i + 1] - x[i])*(m - tmp);
				ans = min(ans, ans1 + dis);
				if (id2 != -1 && tmp - 1 <= m) ans = min(ans, ans2 + x[id2] - x[i] + 1LL * (x[i + 1] - x[i])*(m - tmp - 1));
			}
		}
		if (id2 != -1)
		{
			for (int i = id2; i <= n; i++)
			{
				if (i - id2 + 1 > m || i == 1) continue;
				LL dis = x[i] - x[id2];
				int tmp = i - id2 + 1;
				dis += 1LL * (x[i] - x[i - 1])*(m - tmp);
				ans = min(ans, ans2 + dis);
				if (id1 != -1 && tmp - 1 <= m) ans = min(ans, ans1 + x[i] - x[id1] + 1LL * (x[i] - x[i - 1])*(m - tmp - 1));
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值