洛谷 P1016 旅行家的预算 模拟+贪心

题面

题目链接

P1016 旅行家的预算

题目描述

一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离 $ D_1 $ 、汽车油箱的容量 $ C $ (以升为单位)、每升汽油能行驶的距离 $ D_2 $ 、出发点每升汽油价格 $ P $ 和沿途油站数 $ N $ ( $ N $ 可以为零),油站i离出发点的距离 $ D_i $ 、每升汽油价格 $ P_i (i=1,2,...,N) $ 。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。

输入输出格式

输入格式

第一行,$ D_1,C,D_2,P,N $ 。

接下来有 $ N $ 行。

第 $ i+1 $ 行,两个数字,油站 $ i $ 离出发点的距离 $ D_i $ 和每升汽油价格 $ P_i $ 。

输出格式

所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。

输入输出样例

输入样例

275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2

输出样例

26.95

说明

$ N leq 6 $ , 其他数字 $ leq 500 $

【时空限制】

1000ms,128MB

思路

这道题还真有点麻烦。不过数据规模很小,乱搞搞应该是都能AC的。那我来介绍一种贪心的方法。

首先不妨记起点为第0个加油站,终点为第N+1个加油站且加油价格为0,那么我们可以以如下方式贪心

1.从当前点向后寻找加满油可到的,且油价比当前点小的点。如果当前点不加油可以到达,那么就走过去;否则需要多少油就加多少油(因为走过这个加油站就可以用当前加油站油价更低的油了,多加无用)

2.如果找不到(1)中所述的加油站,那么向后寻找加满油可到的,且油价尽量低的点。然后加满油过去(如果不加满而选择到下一个点加油,那就浪费了)

3.如果没有点可走,那就No Solution

除此之外,如果到终点还有油,那么显然是浪费了。所以我们应该在上一个加油的地方少加一点油,这可以等效为把油带回去卖掉。故每次加油要记录上次加油的位置

AC代码

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

int n;
double L,V,D;
double d[8],w[8];
double ans;

int main()
{
    cin>>L>>V>>D>>w[0]>>n;
    for(int i=1;i<=n;i++) cin>>d[i]>>w[i];
    d[n+1]=L,w[n+1]=0;

    int np=0,last=0;
    double nv=0;
    while(1)
    {
        int v;
        bool f=false;
        for(v=np+1;v<=n+1;v++)
        if(w[v]<w[np] && V>=(d[v]-d[np])/D)
        {
            if(nv>=(d[v]-d[np])/D) nv-=(d[v]-d[np])/D,np=v;
            else ans+=((d[v]-d[np])/D-nv)*w[np],np=v,nv=0,last=np;
            f=true;break;
        }
        if(!f)
        {

            double mi=1000000;
            int p=-1;
            for(v=np+1;v<=n+1;v++)
                if(w[v]<mi && V>=(d[v]-d[np])/D) mi=w[v],p=v;
            if(p==-1) {cout<<"No Solution";return 0;}
            else ans+=(V-nv)*w[np],nv=V-(d[p]-d[np])/D,np=p,last=np;
        }
        if(np==n+1) break;
    }
    ans-=nv*w[last];
    printf("%.2f",ans);
    return 0;
}

总结

1.遇到数据小的题要有多种思路

2.要自己动手模拟

原文地址:https://www.cnblogs.com/Mercury04/p/9762998.html