传送门

题意:

要从高度最低的地方跳到高度最高的地方 每次跳跃的距离小于等于d

每次只能跳到下一个比他高但是和他高度最接近的位置

每个位置都有一个高度值 并且顺序不能换 最低和最高的最远距离。


定义 s [ i ] s[i] s[i]为点 i i i在的位置,这保证了相对位置

可以得到 s [ i ] > s [ i − 1 ] s[i]>s[i-1] s[i]>s[i1]

然后对于高度差相邻的两个序号 u , v u,v u,v为了保证能跳过去

得到 s [ u ] − s [ v ] < = d s[u]-s[v]<=d s[u]s[v]<=d

而且这里一定需要 u > v u>v u>v,因为 u u u在序号上大,所以要远一些的

而且最后是从最矮的位置跑最短路还是从最高的位置,也需要用序号大小来判断

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
const int inf = 1e9;
struct edge{
	int to,nxt,w;
}d[maxn]; int head[maxn],cnt=1;
struct point{
	int id,h;
	bool operator < (const point&tmp )	const{
		return h<tmp.h;
	}
}a[maxn];
int n,m,s,dis[maxn],vis[maxn],num[maxn];
void add(int u,int v,int w)
{
	d[++cnt] = (edge){v,head[u],w},head[u] = cnt;
}
bool spfa(int s)
{
	for(int i=1;i<=n;i++)	dis[i] = inf, vis[i] = num[i] = 0;
	queue<int>q; q.push( s ); dis[s] = 0;
	while( !q.empty() )
	{
		int u = q.front(); q.pop();
		vis[u] = 0;
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v = d[i].to;
			if( dis[v]>dis[u]+d[i].w )
			{
				dis[v] = dis[u]+d[i].w;
				if( !vis[v] )
				{
					q.push( v ),vis[v] = 1;
					if( ++num[v]==n )	return false;
				}
			}
		}
	}
	return 1;
}
int main()
{
	int t,casenum = 0; cin >> t;
	while( t-- )
	{
		cin >> n >> m;
		for(int i=1;i<=n;i++)
		{
			cin >> a[i].h, a[i].id = i;
			if( i>=2 )
				add( i,i-1,-1 );
		}
		sort( a+1,a+1+n );
		for(int i=2;i<=n;i++)
		{
			int u = a[i-1].id, v = a[i].id;
			if( u>v )	swap(u,v);
			add( u,v,m );
		}
		int u = a[1].id, v = a[n].id;
		if( u>v )	swap(u,v);
		cout << "Case " << ++casenum << ": ";
		if( spfa(u) )
			cout << dis[v] <<  endl;
		else
			cout << "-1\n";
		cnt = 1;
		for(int i=1;i<=n;i++)	head[i] = 0;
	}
}