java實現計算最優現金優惠券組合
阿新 • • 發佈:2021-08-10
java實現計算最優現金優惠券組合
在眾多可疊加現金型別優惠券中(比如100減5,200減12等),選出可打折金額最大的組合。
下面程式碼
package com.dk.common.util.algo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * * 計算最優優惠券組合 * */ public class CalcDiscountCouponOptimalCombination { /// ***** 測試 public static void main(String[] args) { double max = 600; List<Item> list = new ArrayList<>(); list.add(new Item(100, 2)); list.add(new Item(100, 3)); list.add(new Item(300, 3)); list.add(new Item(300, 9)); list.add(new Item(300, 4)); list.add(new Item(200, 4)); list.add(new Item(100, 2)); list.add(new Item(200, 9)); list.add(new Item(300, 4)); list.add(new Item(100, 3)); list.add(new Item(230, 3)); list.add(new Item(300, 3)); list.add(new Item(500, 9)); list.add(new Item(300, 4)); list.add(new Item(100, 4)); list.add(new Item(100, 2)); list.add(new Item(400, 9)); list.add(new Item(300, 4)); list.add(new Item(100, 3)); list.add(new Item(230, 3)); for (int i = 0; i < 5; i++) { list.add(new Item(300, 3)); list.add(new Item(500, 9)); list.add(new Item(300, 4)); list.add(new Item(100, 4)); list.add(new Item(100, 2)); list.add(new Item(400, 9)); list.add(new Item(300, 4)); list.add(new Item(100, 3)); list.add(new Item(230, 3)); list.add(new Item(230, 3)); } // ************************ // 券數量多的,建議先按“折扣限制”從大到小排序,可以減少邏輯計算時間 list.sort((o1, o2) -> o1.deduct == o2.deduct ? 0 : o1.deduct > o2.deduct ? -1 : 1); Map<String, Double> maxReduceIdxIssMap = calcMaxReduceIdxIssMap(list, max); System.out.println(maxReduceIdxIssMap); for (String idxIss : maxReduceIdxIssMap.keySet()) { System.out.println("-------------------------------------"); System.out.println(idxIss); String[] idxIsArr = idxIss.split(""); for (int idx = 0; idx < idxIsArr.length; idx++) { String is = idxIsArr[idx]; if ("1".equals(is)) { System.out.println(idx + ": " + list.get(idx)); } } } } /** * 計算最大優惠組合列表 */ public static Map<String, Double> calcMaxReduceIdxIssMap(List<Item> list, double maxAstrict) { Map<String, Double> maxReduceIdxIssMap = new HashMap<>();// 統計極限組合 int len = list.size(); LoopRear lr = new LoopRear() { double currMaxReduce = 0; // idxIss 由0、1組成,1所在下標表示對應項參與了此組合 @Override public boolean runRear(int start, String idxIss, double deductSum, double reduceSum) { boolean haveRear = false;// 後面流程有沒有符合條件的子類組合 String pad = "1"; for (int i = start; i < len; i++) { Item item = list.get(i); double currDeductSum = deductSum + item.deduct;// 當前組合折扣限制總和 double currReduceSum = reduceSum + item.reduce;// 當前組合折扣額度總和 if (currDeductSum <= maxAstrict) { haveRear = true;// 當前組合限制總和小於總金額,表示當前組合的父類不是極限組合(存在子類組合) String currIdxIss = idxIss + pad; boolean haveRearRear = this.runRear(i + 1, currIdxIss, currDeductSum, currReduceSum);// 是否存在子類組合 if (!haveRearRear) { // 不存在子類組合,表示當前組合為一個極限組合 // 比對之前的折扣金額,只保留最大折扣金額的 if (currReduceSum > currMaxReduce) { currMaxReduce = currReduceSum; maxReduceIdxIssMap.clear(); maxReduceIdxIssMap.put(currIdxIss, currReduceSum); } else if (currReduceSum == currMaxReduce) { maxReduceIdxIssMap.put(currIdxIss, currReduceSum); } } } pad = "0" + pad;// 前面下標的項不參與之後組合,後移一位 } return haveRear; } }; lr.runRear(0, "", 0, 0);// 從第一個開始執行 return maxReduceIdxIssMap; } public static class Item { protected double deduct;// 折扣限制,折扣條件 protected double reduce;// 折扣額度 public Item(double deduct, double reduce) { super(); this.deduct = deduct; this.reduce = reduce; } @Override public String toString() { return reduce + "[" + deduct + "]"; } } protected interface LoopRear { boolean runRear(int start, String idxIss, double deductSum, double reduceSum); } }