青蛙表演
问题描述
何老板训练了一只青蛙,该蛙擅长跳跃。它经常从一片荷叶跳到另一片荷叶。今天,何老板打算用N根木桩来向世人展示该蛙的跳跃技能。
这n根木桩排成一行,蛙首先从最矮的木桩顶部起跳,总共进行N-1次跳跃。每次它只能跳到比当前木桩更高的一个木桩顶部。当表演结束时,每个木桩它都恰好到过一次,最终停在最高的木桩顶部。
这只青蛙向上跳跃能力很强,但水平方向跳跃能力就有限了,每次跳跃,它在水平方向飞行的距离不超过D米。舞台上给出的这N根木桩的排列顺序不可改变,但木桩间的间距可以任意调整,但间距必须是整数而且至少为1,且两根木桩不能位于同一点上。何老板想知道,在成功完成表演的前提下,最矮跟最高的那根木桩的间距最大可能是多少?如果无论如何都不能完成表演,输出-1
输入格式
第一行,两个空格间隔的整数N和D
第二行,N个空格间隔的整数,依次给出了每根木桩的高度,不会有相同高度的木桩,木桩的高度在int范围以内。
输出格式
一个整数,表示最矮和最高木桩可能的最大间距
若不可能完成表演,输出-1
样例输入
样例1:
4 4
20 30 10 40
样例2:
4 2
10 20 16 13
样例输出
样例1:
3
样例2:
-1
提示
【样例解释】
样例1说明:
高度20和高度30的木桩的间距可以是1到3之间的任意数字
高度30和高度10的木桩的间距为1
高度10和高度40的木桩的间距为3
跳跃的顺序是:
1.从10跳到20,间距<=4
2.从20跳到30,间距<=4
3.从30跳到40,间距恰好为4。
【数据范围】
对于40%的数据 1 ≤ N ≤ 100
对于100%的数据 1 ≤ N ≤ 1000 ,1 ≤ D ≤1000000
在分析查分约束条件之前,我们应该从题目中知道,由于青蛙一定要到达每一个点,并且只能从矮的跳到高的
也就是说,在我们将点的高度从小到大排序后,所得到的顺序就是青蛙跳的顺序
在增加边的时候,我们可以将排序后数组的下标来当做点,然后再用SPFA求最短路即可
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=2e9;
int n,d;
int Next[1000005],End[1000005],last[1000005],len[1000005];
int dis[1005],cnt,num[1005],iod[1005];
bool f[1005];
queue<int>q;
struct wk{int id,h;}s[1005];
bool cmp(wk a,wk b){return a.h<b.h;}
void iinsert(int a,int b,int l){
End[++cnt]=b;
len[cnt]=l;
Next[cnt]=last[a];
last[a]=cnt;
}
bool spfa(int k){
int i,y,t,x;
for(i=n;i>=1;i--)dis[i]=inf;
q.push(k);
f[k]=true;
dis[k]=0;
num[k]=1;
while(!q.empty()){
x=q.front();
q.pop();
f[x]=false;
t=last[x];
while(t!=0){
y=End[t];
if(dis[x]+len[t]<dis[y]){
dis[y]=dis[x]+len[t];
if(!f[y]){
f[y]=true;
q.push(y);
if(++num[y]>n)return 0;//发现负权回路,则无解
}
}
t=Next[t];
}
}
return 1;
}
int main(){
scanf("%d%d",&n,&d);
int i,ans;
for(i=1;i<=n;i++){
scanf("%d",&s[i].h);
s[i].id=i;
}
sort(s+1,s+1+n,cmp);
for(i=1;i<n;i++)
/约束条件:相邻高度的木桩之间距离不能超过d
if(s[i].id<s[i+1].id)iinsert(i,i+1,d);
else iinsert(i+1,i,d);
for(i=1;i<=n;i++)
iod[s[i].id]=i;//iod数组存的是每一个木桩在s数组中对应的编号
for(i=1;i<n;i++)
iinsert(iod[i+1],iod[i],-1);//约束条件:相邻两点之间距离大于等于1
if(s[1].id<s[n].id)
if(!spfa(1))ans=-1;
else ans=dis[n];
else
if(!spfa(n))ans=-1;
else ans=dis[1];
cout<<ans;
}