• 观光公交


    【题目描述】

    Y市拥有n个美丽的景点。由于慕名而来的游客越来越多,Y市特意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第0分钟出现在1号景点,随后依次前往2、3、4、······、n号景点。从第i号景点开到第i+1号景点需要Di分钟。任意时刻,公交车只能往前开,或在景点处等待。

    设共有m个游客,每位游客需要乘车1次从一个景点到达另一个景点,第i位游客在Ti分钟来到景点Ai,希望乘车前往景点Bi(Ai < Bi)。为了使所有乘客都能顺利到达目的地,公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。

    假设乘客上下车不需要时间。一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司机给公交车安装了k个氮气加速器,每使用一个加速器,可以使其中一个Di减1。对于同一个Di可以重复使用加速器,但是必须保证使用后Di大于等于0。那么司机该如何安排使用加速器,才能使所有乘客的旅行时间总和最小呢?

    【输入描述】

    第1行是3个整数n、m、k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数;
    第2行是n-1个整数,每两个整数之间用一个空格隔开,第i个数表示从第i个景点开往第i+1个景点所需要的时间,即Di;
    第3行至m+2行,每行3个整数Ti、Ai、Bi,每两个整数之间用一个空格隔开。第i+2行表示第i位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。

    【输出描述】

    共一行,包含一个整数,表示最小的总旅行时间。

    【样例输入】

    3 3 2
    1 4
    0 1 3
    1 1 2
    5 2 3

    【样例输出】

    10

    【数据范围及提示】

    对D2使用2个加速器,从2号景点到3号景点时间变为2分钟。
    公交车在第1分钟从1号景点出发,第2分钟到达2号景点,第5分钟从2号景点出发,第7分钟到达3号景点。
    第1个旅客旅行时间7-0=7分钟;
    第2个旅客旅行时间2-1=1分钟;
    第3个旅客旅行时间7-5=2分钟;
    总时间7+1+2=10分钟。

    数据范围:
    对于10%的数据,k=0;
    对于20%的数据,k=1;
    对于40%的数据,2 ≤ n ≤ 50,1 ≤ m≤ 1000,0 ≤ k ≤ 20,0 ≤ Di ≤ 10,0 ≤ Ti ≤ 500;
    对于60%的数据,1 ≤ n ≤ 100,1 ≤ m≤ 1000,0 ≤ k ≤ 100,0 ≤ Di ≤ 100,0 ≤ Ti ≤ 10000;
    对于100%的数据,1 ≤ n ≤ 1000,1 ≤ m ≤ 10000,0 ≤ k ≤ 100000,0 ≤ Di ≤ 100,0 ≤ Ti ≤ 100000。

    源代码:
    
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,k,ans(0),D[1001],G[1001],Sum[1001],Las[1001],Get[1001];
    int T[10001],A[10001],B[10001];
    void Read()
    {
        scanf("%d%d%d",&n,&m,&k);
        for (int a=1;a<n;a++)
          scanf("%d",&D[a]);
        for (int a=1;a<=m;a++)
        {
            scanf("%d%d%d",&T[a],&A[a],&B[a]);
            Sum[B[a]]++;
            Las[A[a]]=max(Las[A[a]],T[a]);
        }
    }
    void Work()
    {
        int Left,Right,Max(0);
        for (int a=1;a<=n;a++)
          if (Sum[G[a]]-Sum[a]>Max&&D[a]>0)
          {
            Max=Sum[G[a]]-Sum[a];
            Left=a;
            Right=G[a];
          }
        Right=min(Right,n-1);
        D[Left]--;
        ans-=Max;
        for (int a=Left;a<=Right;a++)
          Get[a]=max(Get[a-1],Las[a-1])+D[a-1];
        for (int a=Right;a>=Left;a--)
          if (Get[a+1]<=Las[a+1])
            G[a]=a+1;
          else
            G[a]=G[a+1];
    }
    void Print()
    {
        for (int a=1;a<=n;a++)
          Get[a]=max(Get[a-1],Las[a-1])+D[a-1];
        G[n-1]=G[n]=n;
        for (int a=n-2;a>0;a--)
          if (Get[a+1]<=Las[a+1])
            G[a]=a+1;
          else
            G[a]=G[a+1];
        for (int a=1;a<=n;a++)
          Sum[a]+=Sum[a-1];
        for (int a=1;a<=m;a++)
          ans+=Get[B[a]]-T[a];    
        for (int a=0;a<k;a++)
          Work();   
        printf("%d",ans);
    }
    int main()
    {
        Read();
        Print();
        return 0;
    }
  • 相关阅读:
    火星救援
    Android学习笔记(8)————详细谈谈intent的startActivityForResult()方法
    Android小技巧(二):为ContentProvider添加数据库事务支持
    Android小技巧(一):实现捕获应用的运行时异常
    理解Activity的生命周期
    Android异步处理四:AsyncTask的实现原理
    Android异步处理三:Handler+Looper+MessageQueue深入详解
    Android异步处理二:使用AsyncTask异步更新UI界面
    Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
    Android APK反编译详解(附图)
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5768113.html
Copyright © 2020-2023  润新知