从FILL OR NOT FILL【贪心】看分类讨论思想

题目描述

With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time. Different gas station may give different price. You are asked to carefully design the cheapest route to go.

输入描述:

For each case, the first line contains 4 positive numbers: Cmax (<= 100), the maximum capacity of the tank; D (<=30000), the distance between Hangzhou and the destination city; Davg (<=20), the average distance per unit gas that the car can run; and N (<= 500), the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: Pi, the unit gas price, and Di (<=D), the distance between this station and Hangzhou, for i=1,...N. All the numbers in a line are separated by a space.

输出描述:

For each test case, print the cheapest price in a line, accurate up to 2 decimal places. It is assumed that the tank is empty at the beginning. If it is impossible to reach the destination, print "The maximum travel distance = X" where X is the maximum possible distance the car can run, accurate up to 2 decimal places.
解题思路:

1、初始位置0处必须有加油站,要不然没油可加,直接输出最远距离为0,程序停止。
2、根据合法区间【加满后能到达的最远距离与目的地的交集】讨论加油的两种情况:

a、看合法区间是否包含有加油站,若有,在这些加油站中查找价格比当前加油站便宜的,都比当前贵则定稍贵站为 下一站,此时油价是最便宜我们当然选择加满, 注意我们是否有必要到达稍贵站(是否有必要加满),也许可以加到刚好直接到达目的地,所以这里要判断一下当前最大距离是否包含目的地;但凡找到一家比当前便宜的就定 下一站为该加油站。
b、若不包含加油站,则下一站为目的地,加油至刚好能到达目的地即可, 注意当前油量有可能不用加油可以直接抵达目的地
以下是源代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<cmath>
#define MIN 1e-7
using namespace std;

struct st{
double p,D;
bool operator <(const st &A) const{
    if(fabs(D-A.D)<MIN)
        return p<A.p;
    else
        return D<A.D;
}
}buf[500];
int main(){
double Cm=0.00,D=0.00,Davg=0.00,maxs=0.00;
int N;


while((scanf("%lf %lf %lf %d",&Cm,&D,&Davg,&N))!=EOF){//Cm是可加的最大油量,D是目的地距离,Davg是每单位油可以跑的距离,N是油站数量

        maxs=Cm*Davg;

//        printf("%.2f*%.2f=maxs=%.2f\n",Cm,Davg,maxs);
        double s=0,c=0,sum=0;//s走的路程,c是现有的油量,sum是总加油费

        double tmc,tms;
    for(int i=0;i<N;i++){
        cin>>buf[i].p;
        cin>>buf[i].D;
    }
    sort(buf,buf+N);//按距离排序,相同距离的按价格排序
//    cout<<"----------------------"<<endl;
//    for(int i=0;i<N;i++){
//        cout<<buf[i].p;
//        cout<<" ";
//        cout<<buf[i].D<<endl;
//    }
    if(buf[0].D>0){
        printf("The maximum travel distance = %.2f\n",s);
        break;
    }
    for(int i=0;i<N;){
        double minp=9999;
        tms=buf[i].D;
        tmc=(tms-s)/Davg;
        c-=tmc;//走到这里来耗油以后的油量
//        printf("now c is %.2f\n",c);
        s=tms;//当前位置更新
//        cout<<"c="<<c<<endl;


        //--------------------------------------------准备寻下一站--------------------------------------------
      int pos=-1,pos2=-1;//pos记录比当前价格便宜的第一个油站,pos2记录余下加油站中价格最便宜的一个油站

//      printf("now is %lf\n",buf[i].D);
//      printf("sum is %.2lf\n",sum);
      for(int j=i+1;j<N;j++){//查找余下的加油站

//        printf("-> %lf\n",buf[j].D);
        tms=buf[j].D-buf[i].D;
        if(tms>maxs||buf[j].D>D){//不属于合法区间
//            printf("tms=%.2f\n",tms);
            if(tms>maxs)
//            printf("next s is %.2f impossibly\n",buf[j].D);
//            if(tms>maxs)
//            printf("!maxs=%.2f\n",maxs);
//            if(buf[j].D>D)
//            printf("!!buf[j].D=%.2f D=%.2f\n",buf[j].D,D);
            break;
        }
        if(buf[j].p<buf[i].p){//有更便宜的

            pos=j;
//            cout<<"!"<<endl;
            break;
        }
        if(buf[j].p<minp){

            minp=buf[j].p;
            pos2=j;
//            cout<<"!!"<<endl;
        }
      }
//      cout<<"!!!"<<endl;
      if(pos==-1&&pos2==-1){//合法区间内没有加油站或加油站已遍历完
        tms=D-s;
//        printf("maxs=%.2f\n",maxs);
//        printf("tms=%.2f\n",tms);
        if(tms>maxs){//无法到达目的地
            s+=maxs;
            printf("The maximum travel distance = %.2f\n",s);
        }
        else{//可以到达则加油到刚好能到达

            tmc=tms/Davg;//需要的油量
            if(tmc>c){//看看还要不要加油
                tmc=tmc-c;//还要加的油量
                sum+=tmc*buf[i].p;
            }
            printf("%.2lf\n",sum);
        }
        break;
      }
      else{

        if(pos!=-1){//下一最优站比当前站便宜->加到刚好到达
        tms=buf[pos].D-s;
        tmc=tms/Davg-c;
        sum+=tmc*buf[i].p;
//        printf("!sum=%.2f\n",sum);
        c=tms/Davg;
        i=pos;
      }
      else{//下一最优站比当前站贵->加满(考虑不用加满就可以直达目的地的情况)


        if(maxs>(D-s)){//!!!!!!!!!!!!!!!!老娘就是这个地方大意了哇!!!!!!!!!!!!!!!!


            tms=D-s;
            tmc=tms/Davg;//需要的油量
            if(tmc>c){//看看还要不要加油
                tmc=tmc-c;//还要加的油量
                sum+=tmc*buf[i].p;
            }

            printf("%.2lf\n",sum);
            break;
        }
        else{
        tmc=Cm-c;
        sum+=tmc*buf[i].p;
//        printf("!!sum=%.2f\n",sum);
        c=Cm;
        i=pos2;
        }

      }
      }


}

}


return 0;
}

 

笔记:
1、double可以用%f/%lf来输出,但必须用%lf输入,不为什么。

2、当数据从低精度到高精度时,不会引起精度的丢失,尽量使用doubl而非float来处理浮点数。
3、float类型的有效位是6-7位,double类型有效位是15-16位,必要时用long double。

4、浮点数比较大小可以直接比,但是相等的话一半采用fabs(a-b)<1e-7的方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值