CSP歷年複賽題-P1016 [NOIP1999 提高組] 旅行家的預算

江城伍月發表於2024-05-21

原題連結:https://www.luogu.com.cn/problem/P1016

題意解讀:用最少的加油費用到達另一個城市,中間有若干加油點,起點也可加油。

解題思路:

本題是一個貪心策略題:

列舉每一個加油點i:

1、初始加油點是起點

2、汽車能跑的最大距離範圍內,找到下一個更便宜的加油點的位置

3、如果能找到更便宜的加油點j,則在i點加的油只需滿足能跑到j點即可

4、如果在最大距離範圍內找不到更便宜的加油點

  看看從i點能否直接跑到終點,如果可以在i點加的油滿足能跑到終點即可

  如果從i點無法跑到終點,則在i點加滿油,並在最大距離範圍內找價錢最便宜的加油點j

加油點i設定為j,繼續列舉。。。

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

double d1; //兩個城市距離
double c; //郵箱容量(升)
double d2; //每升汽油行使距離
double p; //起點油價
int n; //加油站數量

double dist[10]; //每個加油點距離起點的距離,包括起點和終點,起點是0,終點是d1
double price[10]; //每個加油點的油價,起點是p,終點是1e9

double ans;

int main()
{
    scanf("%lf%lf%lf%lf%d", &d1, &c, &d2, &p, &n);
    dist[1] = 0, price[1] = p;
    for(int i = 1; i <= n; i++)
    {
        scanf("%lf%lf", &dist[i + 1], &price[i + 1]);
    }
    dist[n + 2] = d1, price[n + 2] = 1e9;

    double maxdist = c * d2; //maxdist表示加滿油最多行使的距離
    double rest = 0; //郵箱剩餘油量

    for(int i = 2; i <= n + 2; i++)
    {
        if(dist[i] - dist[i - 1] > maxdist) //如果兩點之間距離超過加滿油可行駛最大距離,則無解
        {
            cout << "No Solution";
            return 0;
        }
    }

    int i = 1; //i列舉每個加油點,從起點開始
    while(i <= n + 1)
    {
        //在可以行使的最大距離內,找到第一個比i點便宜的加油點
        bool yes = false;
        int j;
        for(j = i + 1; j <= n + 1 && dist[j] - dist[i] <= maxdist; j++)
        {
            if(price[j] < price[i]) 
            {
                yes = true;
                break;
            }
        }

        if(yes) //有找到便宜的加油點
        {
            ans += ((dist[j] - dist[i]) / d2 - rest) * price[i]; //在i點加油能跑到j點即可
            rest = 0; //到j點後剩下的油量
        }
        else //沒有找到便宜的加油點
        {
            if(dist[n + 2] - dist[i] <= maxdist) //沒有更便宜的加油點,但可以跑到終點
            {
                ans += ((dist[n + 2] - dist[i]) / d2 - rest) * price[i]; //直接加油夠跑到終點
                break; //結束
            }
            else //不能跑到終點
            {
                ans += (c - rest) * price[i];  //則在i點把郵箱加滿

                double minp = 2e9, mini = i;
                //找到i之後j之前價格最低的點
                for(int k = i + 1; k < j; k++)
                {
                    if(price[k] < minp)
                    {
                        minp = price[k];
                        mini = k;
                    }
                }
                j = mini; //下次從價格最低的點加油
                rest = c - (dist[j] - dist[i]) / d2; //到j點後剩下的油量
            }
            
        }
        i = j; //下一個加油點是j
    }

    printf("%.2lf", ans);

    return 0;
}

相關文章