CSP历年复赛题-P1016 [NOIP1999 普及组] 旅行家的预算

原题链接: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;
}

 

posted @ 2024-05-21 11:47  五月江城  阅读(32)  评论(0编辑  收藏  举报