笔试题目:RMB组合,有如下RMB 面额, 1,2,5,10,20,50,100,给定各面额纸币数和RMB总额,求组合方案——递归回溯算法

8 篇文章 0 订阅
1 篇文章 0 订阅

RMB组合,有如下RMB 面额, 1,2,5,10,20,50,100,给定一个RMB总额,求组合方案。各纸币面额数没有限制。
动态规划实现参考:https://blog.csdn.net/qq_33619378/article/details/82748576
如果需要纪录各方案使用的面额,则得使用递归回溯,纪录到List,代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Title:
 * Description:递归
 * <p>
 * RMB面额:1 2 5 10 20 50 100
 * 给定一个总额,求组合方案,面额纸币数量不限制且无限
 *
 * @author WZQ
 * @version 1.0.0
 * @date 2021/3/26
 */
public class Money01 {

    // 面额
    static int[] money = {1, 2, 5, 10, 20, 50, 100};

    static List<List<Integer>> result = new ArrayList<>();

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        dfs(new ArrayList<>(), 0, n, 0);
        // 打印结果
        for (List<Integer> list : result) {
            System.out.println(list);
        }
    }

    /**
     * 递归回溯
     *
     * @param lists   存放已选
     * @param sum     总额
     * @param current 当前额
     */
    public static void dfs(List<Integer> lists, int k,  int sum, int current) {
        if (sum == current) {
            // 符合的结果,需要重新new
            result.add(new ArrayList<>(lists));
        }

        if (sum <= current || k >= 7 || sum < current + money[k]) {
            return;
        }

        // 各种面值递归
        for (int i = k; i < money.length; i++) {
            lists.add(money[i]);

            dfs(lists, i, sum, current + money[i]);

            // 回溯,删除最后一个
            lists.remove(lists.size() - 1);
        }
    }

    /**
     * 动态规划
     * @param n 总额
     */
    public static void dy(int n) {
        // 纸币面额
        int[] money = {1, 2, 5, 10, 20, 50, 100};
        // 当前总额的组合数
        int[] dp = new int[n + 1];
        dp[0] = 1;
        for (int i = 0; i < 7; ++i) {
            // 公式
            for (int j = money[i]; j <= n; ++j) {
                dp[j] = (dp[j] + dp[j - money[i]]);
            }
        }
        System.out.println(dp[n]);
    }

}

问题进阶:RMB组合, 有如下RMB 面额, 1,2,5,10,20,50,100,给定各纸币面额数量和RMB总额,求组合方案,打印各方案的选择,这里不是计数,而且各面额纸质数量有限制,题目输入。
递归回溯算法:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

/**
 * Title:
 * Description:递归回溯
 * <p>
 * RMB面额:1 2 5 10 20 50 100
 * 给定各面额纸质数和一个总额,求组合方案
 *
 * @author WZQ
 * @version 1.0.0
 * @date 2021/3/26
 */
public class Money02 {

    // 面额
    static int[] money = {1, 2, 5, 10, 20, 50, 100};

    // 统计面额纸币数
    static Map<Integer, Integer> maps = new HashMap<>();

    static List<List<Integer>> result = new ArrayList<>();

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // 输入每种面额纸币数
        for (int i = 0; i < 7; i++) {
            int m = input.nextInt();
            maps.put(money[i], maps.getOrDefault(money[i], 0) + m);
        }

        dfs(new ArrayList<>(), 0, n, 0);

        // 打印结果
        for (List<Integer> list : result) {
            System.out.println(list);
        }
    }

    /**
     * 递归回溯
     *
     * @param lists   存放已选
     * @param k 当前位置,后面比前大,保证顺序和唯一
     * @param sum     总额
     * @param current 当前额
     */
    public static void dfs(List<Integer> lists, int k, int sum, int current) {
        if (sum == current) {
            // 符合的结果,需要重新new
            result.add(new ArrayList<>(lists));
        }

        if (sum <= current || k >= 7 || sum < current + money[k]) {
            return;
        }

        // 各种面值递归,只能大于等于k
        for (int i = k; i < 7; i++) {
            if (maps.get(money[i]) >= 1){
                // 使用该面额纸币
                lists.add(money[i]);
                maps.put(money[i], maps.get(money[i]) - 1);

                dfs(lists, i , sum, current + money[i]);

                // 回溯
                lists.remove(lists.size() - 1);
                maps.put(money[i], maps.get(money[i]) + 1);
            }
        }
    }

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wzq_55552

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值