ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P1016 [NOIP1999 提高组] 旅行家的预算

2021-01-31 19:29:33  阅读:232  来源: 互联网

标签:便宜 price P1016 st 站点 NOIP1999 now 旅行家 dis


P1016 [NOIP1999 提高组] 旅行家的预算

这道题,哇,花了我好久的时间啊,我太菜了,所以决定好好地写一写博客,整理一下思路~
先来看一遍题目
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离D1、汽车油箱的容量C(以升为单位)、每升汽油能行驶的距离D2、出发点每升汽油价格P和沿途油站数N(N可以为零),油站i离出发点的距离Di、每升汽油价格Pi(i=1,2,…,Ni=1,2,…,N)。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。
思路奉上
我的废物思路就不说了,浪费时间,记录一下可行思路
首先要排序
按照离起点由近到远的距离排序
一个for循环遍历排好序的数组,当找到下一个站点:
(1)当前站点加油后,可到达下一个站点(即两站距离小于当前的maxn,maxn:当前油箱里的油可以走的最远距离),且这个站点的油比当前站点要便宜。
因为可以找到这样的一个站点,所以我们只需在当前站点加多少油呢?刚好到那个站点时油耗尽代码中对应res=0
为什么for循环找到的第一个满足条件的站点就可以用呢?难道for循环后面没有更便宜的了嘛
答:因为站点是按远近排的,当前找到的站点虽然不一定比后面的便宜,但贪心策略只看当下,当下换上更便宜的油,比用之前贵的油走到后面找便宜的油要合适。
所以代码是这样的:

	    if(st[i].price<st[now].price)//能到&&便宜
        {
            price_sum+=(st[i].dis-st[now].dis)/d2*st[now].price;
            res=0;//res代表剩余油量可走路程
            return i;
        }

(2)找到了能到的站点,但是不比当前站点便宜,这时我们的策略是:用最便宜的油走最远的路
所以这时候我们要用一个标记变量,标记for循环可执行的最后,为什么呢?因为要用最便宜的油走到最远的地方,当前站点是最便宜的,for途径的都比他贵
为什么这时候for循环的都比他贵呢?
因为如果有比他便宜的,在上面的代码里就return了。
所以代码是这样的:

	if(index==wrong||st[i].price<st[index].price)
            index=i;//能到but不便宜

(1)和(2)是在一个for循环里的,接下来的情况就是走出了for循环,也就是(2)的后续延伸情况
第一种:就是虽然没有更便宜的站点,但是,当前站点加油之后可以直接走到终点

if(d1-st[now].dis<=maxn)//没有更便宜的,且能到终点了
    {
        price_sum+=(d1-st[now].dis-res)/d2*st[now].price;
        return wrong;
    }

第二种:就是刚才的for循环根本没有找到一个可以走的站(即就算本站加满,也走不到下一站或终点)

 if(index==wrong)
    {
        //到不了下个站
        cout<<"No Solution"<<endl;
        return -1;
    }

第三种:就是普通情况,我们用最便宜的油一直走到他可以走到的最远的站,然后加油

	else//没有更便宜的,又不能一次到终点
    {
        price_sum+=c*st[now].price;
        res+=(maxn-(st[index].dis-st[now].dis));
        return index;
    }

好了,思路就是这样,整理一下,看代码~
完整代码

#include <bits/stdc++.h>

using namespace std;
typedef struct
{
    double dis;
    double price;
}station;
int wrong=99999;
station st[100000];
double d1,c,d2,p;
int n;
int now;//当前所在位置
int t;
double maxn;//最远走到哪里

double res;//剩余;
double price_sum=0;//总价钱
int cmp(station a,station b)
{
    return a.dis<b.dis;
}
int func(int now)
{
    int index=wrong;//next
    for(int i=now+1;i<=n&&st[i].dis-st[now].dis<=maxn;i++)//找能到的加油站
    {
        if(st[i].price<st[now].price)//能到&&便宜
        {
            price_sum+=(st[i].dis-st[now].dis)/d2*st[now].price;
            res=0;
            return i;
        }
        if(index==wrong||st[i].price<st[index].price)
            index=i;//能到,不便宜

    }
    if(d1-st[now].dis<=maxn)//没有更便宜的,且能到终点了
    {
        price_sum+=(d1-st[now].dis-res)/d2*st[now].price;
        return wrong;
    }
    if(index==wrong)
    {
        //到不了下个站
        cout<<"No Solution"<<endl;
        return -1;
    }

    else//没有更便宜的,又不能一次到终点
    {
        price_sum+=c*st[now].price;
        res+=(maxn-(st[index].dis-st[now].dis));
        return index;
    }
}
int main()
{

    cin>>d1>>c>>d2>>p>>n;

    st[0].dis=0;
    st[0].price=p;
    for(int i=1;i<=n;i++)
    {
        cin>>st[i].dis>>st[i].price;
    }

    sort(st,st+n+1,cmp);
    now=0;
    maxn=c*d2;

    do
    {
        t=func(now);
        now=t;
        if(t==-1)
            return 0;
    }while(t!=wrong);

    cout<<fixed<<setprecision(2)<<price_sum<<endl;
    return 0;
}

呼~本以为贪心算法要比动态规划简单的多,没想到这道题也花了我好长时间,菜鸡·明
思路有点乱,写的也有点乱,希望大家可以看懂~

标签:便宜,price,P1016,st,站点,NOIP1999,now,旅行家,dis
来源: https://blog.csdn.net/qq_51052824/article/details/113482657

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有