算法题-模拟商场优惠打折

模拟商场优惠打折:

有三种优惠可以用,满减券,打折券和无门槛券

满减券:满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);
    }




}
复制代码

 

posted @   Mars.wang  阅读(397)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示