贪心算法-PAT 1033 To Fill or Not to Fill

**

贪心算法典型例题01

**
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.
Input Specification:

Each input file contains one test case. 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.

Output Specification:

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.

Sample Input 1:
50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300
Sample Output 1:
749.17
Sample Input 2:
50 1300 12 2
7.10 0
7.00 600
Sample Output 2:
The maximum travel distance = 1200.00
题目大意:驾车从杭州出发,通过高速公路到达某一目的地距离dis,由于油箱cMax有限,必须去加油站加油,路途上各个加油站的油价均有差异,需要找到一条通往目的花费最低的一条方案。dAvg表示平均每单位的汽油让汽车行驶的距离,加油站的个数为N,每个加油站的价格为price,距离起点的距离为dist。

分析:贪心算法,核心思想通过局部最优解求得全局最优解。当汽车在某一加油站,此时司机可以选择加满油,也可以选择加油到刚好到下一加油站,取决于后续加油站的油价。

0.当下一个加油站的价格比当前加油站的价格低,选择加油到刚好行驶到下一个加油站。
1.如果司机发现当前即使加满油,行驶的最大范围内没有比当前加油站的价格还要低的加油站,那么我们选择加满油到下一个加油站。

循环这个两个选择,直到行驶到目的地。通过求得此时此刻最优的解来解决全局最优解,这是贪心算法的核心思想,读者需要仔细体会。

作者也是算法的学习者,本文也是参考柳神的算法宝典:
柳神–贪心算法专题

import java.util.*;

/**
 * @author chengqian
 * @create 2020-07-07 14:12
 * Tag = 贪心算法
 */
class Sta implements Comparable<Sta>{
    double price;
    double dist;

    public Sta(double price, double dist) {
        this.price = price;
        this.dist = dist;
    }

    public int compareTo(Sta o) {
        return (int)(this.dist - o.dist);
    }
}

public class Test01 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        double cMax = scan.nextDouble(); // 油箱最大容量
        double dis = scan.nextDouble();  // 起点到终点的距离
        double dAvg = scan.nextDouble(); //每升汽油单位距离
        int n = scan.nextInt();


        List<Sta> list = new ArrayList<Sta>();
        list.add(new Sta(0.0, dis));
        for (int i = 0; i < n; i++) {
            double d1 = scan.nextDouble();
            double d2 = scan.nextDouble();
            list.add(new Sta(d1, d2));
        }
        Collections.sort(list);

        double nowDis = 0, maxDis = 0, nowPrice = 0, totalPrice = 0, leftDis = 0;
        //当起点没有油,则最大的行驶距离为0
        //leftDis为油量为0是,跑到最远距离。表示当前加油站不加油的情况下。

        if (list.get(0).dist > 0){
            System.out.printf("The maximum travel distance = 0.00");
            return;
        }
        nowPrice = list.get(0).price;


        while (nowDis < dis){
            maxDis = nowDis + cMax * dAvg; //当前加油站加满油行驶的最远距离
            double minPrice = Double.MAX_VALUE, minPriceDis = 0;
            boolean flag = false;//表示flag=true,表示找到价格更低的加油站。
            //在可到的范围内找到价格最低的加油站

            for (int i = 1; i <= n && list.get(i).dist <= maxDis; i++) {
                if (list.get(i).dist <= nowDis) continue; //跳过已经经过的加油站
                if (list.get(i).price <= nowPrice){ //在可到范围找最近且价格更低的加油站
                    totalPrice += (list.get(i).dist - nowDis - leftDis) / dAvg * nowPrice;
                    //leftDis < list.get(i)[1] - nowDis, 因为这是当前节点不可能达到的点。
                    nowDis = list.get(i).dist;
                    nowPrice = list.get(i).price;  //因为能到下一个点,所以刷新一下最新的价格和距离
                    leftDis = 0;   //因为下一次位置油耗完刚到下一个加油站
                    flag = true;   //表示上一个加油站是踩点的加油站
                    break;
                }
                if (list.get(i).price < minPrice){ //当可到范围内没有价格更低的加油站
                    minPrice = list.get(i).price;
                    minPriceDis = list.get(i).dist;
                }
            }

            if(!flag && minPrice < Double.MAX_VALUE){
                totalPrice += nowPrice * (cMax - leftDis/dAvg);
                leftDis = cMax * dAvg - (minPriceDis - nowDis);
                nowDis = minPriceDis;
                nowPrice = minPrice;
            }

            if(!flag && minPrice == Double.MAX_VALUE){
                nowDis += cMax * dAvg;
                System.out.printf("The maximum travel distance = %.2f", nowDis);
                return;
            }
        }

        System.out.printf("%.2f", totalPrice);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值