NKOI 5月月赛 青蛙表演

                                                                                                                                  青蛙表演
时间限制 : 10000 MS   空间限制 : 165536 KB
问题描述

何老板训练了一只青蛙,该蛙擅长跳跃。它经常从一片荷叶跳到另一片荷叶。今天,何老板打算用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;
} 



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值