算法题-模拟商场优惠打折
模拟商场优惠打折:
有三种优惠可以用,满减券,打折券和无门槛券
满减券:满100减10,满200减20,依次递推
打折券:92折,每次打折完向下取整,一次购物只能用一次
无门槛券:一张券减5元,多张券可以累加,没有使用限制
结账是有以下限制:
每人每次只能只有两种优惠券,一种券必须一次性用完,不能穿插使用
求不同使用顺序下每人用完券后的最低价格和使用券数,如果两种策略使用后的价格一样低,则优先选择使用券数更少的那个
输入描述:
第一行: m n k分别代表三种券的数量
第二行: x 代表购物人数
第三到最后: 代表x人每人的购物金额
输出描述
每个人优惠后的金额和使用券数,按输入顺序排序
首先创建促销策略类和三种策略实现
/** * @Author : wangbin * @Date : 2023/2/27 13:47 * @Description: 优惠策略,入参是原价和原优惠券数,返回值是优惠的价格和用掉的优惠券 */ public interface PromotionStrategy { /** * 优惠要受限于优惠券的数量 * @param originPrice 原价 * @param originCoupon 优惠券数 * @return Preferential */ Preferential apply(int originPrice,int originCoupon); //优惠记录 @Data @NoArgsConstructor @AllArgsConstructor static class Preferential { //折后价 private int afterDiscount; //用掉的优惠券 private int couponNum; } }
满减策略类
/** * @Author : wangbin * @Date : 2023/2/27 13:48 * @Description: 满减,满100减10,满200减20,依次类推 */ public class PromotionStrategyFullReduction implements PromotionStrategy { @Override public Preferential apply(int originPrice, int originCoupon) { if (originCoupon <= 0) { return new Preferential(originPrice, 0); } int couponNum = Math.min(originPrice / 100, originCoupon); return new Preferential(originPrice - couponNum * 10, couponNum); } public static void main(String[] args) { PromotionStrategyFullReduction reduction = new PromotionStrategyFullReduction(); Preferential apply = reduction.apply(200, 2); System.out.println(apply); } }
折扣策略类
/** * @Author : wangbin * @Date : 2023/2/27 13:47 * @Description: 92折券, 减完如果非整数,向下取整,例如:165.5->165 */ public class PromotionStrategyDiscount implements PromotionStrategy { private static final float DIS = 0.92f; @Override public Preferential apply(int originPrice, int originCoupon) { if (originCoupon <= 0) { return new Preferential(originPrice, 0); } int afterDiscount = (int) Math.floor(originPrice * DIS); return new Preferential( afterDiscount, 1); } public static void main(String[] args) { PromotionStrategyDiscount discount = new PromotionStrategyDiscount(); Preferential apply = discount.apply(180, 0); System.out.println(apply); } }
立减策略类
/** * @Author : wangbin * @Date : 2023/2/27 13:48 * @Description: 立减券,每次减5元,有多少减多少 */ public class PromotionStrategyImmediateReduction implements PromotionStrategy { @Override public Preferential apply(int originPrice, int originCoupon) { if (originCoupon <= 0) { return new Preferential(originPrice, 0); } int couponNum = Math.min(originPrice / 5, originCoupon); return new Preferential(originPrice - couponNum * 5, couponNum); } public static void main(String[] args) { PromotionStrategyImmediateReduction reduction = new PromotionStrategyImmediateReduction(); Preferential apply = reduction.apply(200, 0); System.out.println(apply); } }
这个题目的难度在于策略是可以叠加使用的,而且可以选择叠加顺序且限制只能叠加两种,所以需要构造出三种策略选二的所有排列数
我们使用以工具类完成这一要求
class Permutation { private final List<List<Integer>> lists = new ArrayList<>(); public List<List<Integer>> permute2(int[] nums,int limit ) { //数组长度 int n = nums.length; //阶段性成果 List<Integer> list = new ArrayList<>(n); //状态数组 boolean[] used = new boolean[n]; //排列中数的个数 int count = 0; //开始深度优先搜索 backtrace(list, used, count, nums,limit); return lists; } public void backtrace(List<Integer> list, boolean[] used, int count, int[] nums, int limit ) { if (count == limit) { lists.add(new ArrayList<>(list)); return; } for (int i = 0; i < used.length; i++) { if (!used[i]) { list.add(nums[i]); used[i] = true; backtrace(list, used, count + 1, nums,limit); list.remove(list.size() - 1); used[i] = false; } } } public static void main(String[] args) { Permutation permutation = new Permutation(); List<List<Integer>> permute = permutation.permute2(new int[]{1, 2, 3},2); for (List<Integer> integers : permute) { System.out.println(integers); } } }
最终的执行主类
public class Main { private static final List<PromotionStrategy> strategies = new ArrayList<>(); private static final List<Integer> coupons = new ArrayList<>(); public static void main(String[] args) { Scanner in = new Scanner(System.in); //满减、打折、立减券数 int mj = in.nextInt(); int dz = in.nextInt(); int lj = in.nextInt(); int N = in.nextInt(); List<Integer> priceList = new ArrayList<>(); for (int i = 0; i < N; i++) { priceList.add(in.nextInt()); } //构造策略工厂 buildStrategyFactory(mj, dz, lj); for (int i = 0; i < N; i++) { Integer price = priceList.get(i); //限定每次只能选两种策略,求最优解 PromotionStrategy.Preferential preferential = optimalStrategy(price, 2); System.out.format("%d %d\n", preferential.getAfterDiscount(), preferential.getCouponNum()); } } /** * 这些策略和优惠券数量是不变的,可以一次性初始化 * * @param mj * @param dz * @param lj */ public static void buildStrategyFactory(int mj, int dz, int lj) { strategies.add(new PromotionStrategyFullReduction()); strategies.add(new PromotionStrategyDiscount()); strategies.add(new PromotionStrategyImmediateReduction()); coupons.add(mj); coupons.add(dz); coupons.add(lj); } public static PromotionStrategy.Preferential optimalStrategy(int originPrice, int strategyLimit) { //构造从三种策略取两种的全排列 Permutation permutation = new Permutation(); List<List<Integer>> strategyPermutationList = permutation.permute2(new int[]{0, 1, 2}, strategyLimit); int minPrice = originPrice; int minCoupon = Integer.MAX_VALUE; for (List<Integer> strategyPermutation : strategyPermutationList) { int price = originPrice; int couponSum = 0; for (int i : strategyPermutation) { PromotionStrategy strategy = strategies.get(i); Integer couponNum = coupons.get(i); PromotionStrategy.Preferential apply = strategy.apply(price, couponNum); price = apply.getAfterDiscount(); couponSum += apply.getCouponNum(); } //最优的优惠策略组合是最终折后价最低,如果折后价相同,消耗的优惠券最少 if (price < minPrice) { minPrice = price; minCoupon = couponSum; } else if (price == minPrice) { if (couponSum < minCoupon) { minCoupon = couponSum; } } } return new PromotionStrategy.Preferential(minPrice, minCoupon); } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)