羊城通薅羊毛6折公交算法


前言

本碼農每天地鐵通勤上下班,按平均計算每月需要上班的工作日為22天,即需要刷地鐵44次。

羊城通優惠如下

  1. 每月刷公交前15次按票價 95折 計算,最低票價為2元
  2. 每月刷公交滿15次后按票價 6折 計算
  3. 每月優惠清零。即每個月都需要刷15次后才有6折優惠

想法

如果我每月初先按最低的 2元票價刷滿15次 ,接下來上下班通勤就都有6折了,這樣能不能省下點~.... [手動dog]

開工...


public class Main {

    public static void main(String[] args) {
        getMostEconomicalSolution(8, 16);
    }

    /**
     * 計算最低成本方案
     *
     * @param numberOfRidesRequired 通勤次數
     * @param normalFare            通勤票價
     * @return
     */
    private static Double getMostEconomicalSolution(Integer numberOfRidesRequired, Integer normalFare) {
        Integer bastCount = 0;
        Double bastFace = null;
        for (int i = 0; i <= 15; i++) {
            Double fare = operatingMetroFareCalculation(numberOfRidesRequired, normalFare, i);
            System.out.println("操作" + i + "次成本為" + fare);

            if (i == 0) {
                bastFace = fare;
            } else {
                if (fare < bastFace) {
                    bastFace = fare;
                    bastCount = i;
                }
            }
        }

        Double normaTotal = normalMetroFareCalculation(numberOfRidesRequired, normalFare);

        if (bastFace < normaTotal) {
            System.out.println("最佳操作次數為:" + bastCount + "次,成本為:" + bastFace);
            System.out.println("原始成本為:" + normaTotal + ",可節約 " + (normaTotal - bastFace) + " 元。");
        } else {
            System.out.println("最佳操作次數為:0次,成本為:" + normaTotal);
            System.out.println("原始成本為:" + normaTotal + ",可節約 0 元。");
        }
        return bastFace;
    }

    /**
     * 計算先按最低票價2元刷次數以及通勤的總費用
     *
     * @param numberOfRidesRequired 通勤次數
     * @param normalFare            通勤票價
     * @param operatingCount        低價刷次數
     * @return
     */
    private static Double operatingMetroFareCalculation(Integer numberOfRidesRequired, Integer normalFare, Integer operatingCount) {
        if (operatingCount < 0 || operatingCount > 15) throw new RuntimeException("操作次數必須在0~15之間");

        if (numberOfRidesRequired > (15 - operatingCount)) {
            return operatingCount * 2 * 0.95
                    + (15 - operatingCount) * normalFare * 0.95
                    + normalFare * (numberOfRidesRequired - 15 + operatingCount) * 0.6;
        } else {
            return operatingCount * 2 * 0.95
                    + numberOfRidesRequired * normalFare * 0.95;
        }
    }

    /**
     * 計算正常通勤總費用
     *
     * @param numberOfRidesRequired 通勤次數
     * @param normalFare            通勤票價
     * @return
     */
    private static Double normalMetroFareCalculation(Integer numberOfRidesRequired, Integer normalFare) {
        if (numberOfRidesRequired > 15) {
            return 15 * normalFare * 0.95 + (numberOfRidesRequired - 15) * normalFare * 0.6;
        } else {
            return numberOfRidesRequired * normalFare * 0.95;
        }
    }
}


計算

按44次通勤,票價5元計算

按44次通勤,票價6元計算

按44次通勤,票價7元計算

按15次通勤,票價6元計算

方程式

設差價為N,通勤次數為X,通勤單價為Y,低價先刷卡操作次數為Z,
設正常通勤總費用為O,操作后通勤總費用為P

方案A:當通勤次數 X > 15 時,


O=15×0.95Y+(X-15)×0.6Y=14.25Y+0.6XY-9Y=5.25Y+0.6XY ,

P=2×0.95Z+(15-Z)×0.95Y+(X-(15-Z))×0.6Y=1.9Z+14.25Y-0.95ZY+0.6XY-9Y+0.6ZY=1.9Z+0.6XY+5.25Y-0.35ZY ,

則 N=O-P
    =5.25Y+0.6XY-(1.9Z+0.6XY+5.25Y-0.35ZY)
    =0.35ZY-1.9Z
    =(0.35Y-1.9)×Z

由此可得

  1. 差價與通勤次數X無關,差價由通勤單價Y 以及刷卡操作次數Z決定,當通勤單價Y滿足條件 0.35Y-1.9 ≦ 0 時,即 Y ≦ 5.428元時,差價小於等於零。
  2. 當通勤單價高於5.428元時,低價先刷卡操作次數越多越好,即直接刷滿15次即可。

方案B:當通勤次數 X ≦ 15 ,且 X > 15-Z 時 (略)

方案B:當通勤次數 X ≦ 15 ,且 X <= 15-Z 時 (略)

結論

  1. 通勤單價如果少於5.428元錢就不划算了,不用考慮
  2. 當通勤單價高於5.428元時,低價先刷卡操作次數越多越好,即直接刷滿15次即可。
  3. 好吧~其實吧...也省不了多少錢,還是多搞幾個Bug吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM