算法小练习之取球方案

200 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

1、前言

每天一个算法小练习,本篇使用Java实现。

2、题目描述

  有K种颜色的小球(K<=10),每种小球有若干个,总数小于100个。现在有一个小盒子,能放N个小球(N<=8),现在要从这些小球里挑出N个小球,放满盒子。想知道有哪些挑选方式。注:每种颜色的小球之间没有差别。请按数字递增顺序输出挑选小球的所有方式。
如有3种颜色,每种颜色小球的个数分别为a:1,b:2,c:3,挑出3个小球的挑法有:003,012,021,102,111,120。

2.1、输入描述

第一行两个数字K N,分别表示小球种类数目和挑选的小球个数;
第二行开始为每种小球的数目,共K行数据。

2.2、输出描述

输出所有可行的挑选方案,按升序排列.

2.3、示例1

输入:

3 3
1
2
3

输出:

003
012
021
102
111
120

3、解题思路

3.1、递归

每种小球分别取0~max值

3.1.1、实现代码

public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            int k = sc.nextInt();
            int n = sc.nextInt();
            //记录颜色球的个数
            int[] nums = new int[k];
            for(int i = 0;i < k; i++){
                nums[i] = sc.nextInt();
            }
            List<String> result = new LinkedList<>();
            recursion(result,n,0,nums,"");
            result.forEach(System.out::println);
        }
    }

    /**
     * 利用递归思想,深度优先遍历
     * @param result
     * @param target
     * @param start
     * @param nums
     * @param s
     */
    public static void recursion(List<String> result,int target,int start,int[] nums,String s){
        if(target == 0 && start == nums.length){
            result.add(s);
            return;
        }
        if(start == nums.length){
            return;
        }
        for(int i = 0;i <= Math.min(target,nums[start]);i++){
            // 取当前 target 和对应球的数量中的较小值。
            recursion(result,target - i,start+1,nums,s+i);
        }
    }

3.1.2、执行结果

image.png

3.2、for循环

采用3层for循环,分别计算出取每种球之前有几种方案,最后输出结果。

3.2.1、实现代码

/**
     * 两个List嵌套,记录取球方案
     */
    private static List<List<Integer>> reslut = new ArrayList<>();

    private static List<String> resStr = new LinkedList<>();

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int k = scanner.nextInt();
            int n = scanner.nextInt();
            int[] colors = new int[k];
            for (int i = 0; i < k; i++) {
                colors[i] = scanner.nextInt();
            }
            testBall(colors, k, n, 0);
            resStr.forEach(System.out::println);
        }
    }

    public static void testBall(int[] colors, int k, int n, int level) {
        if (k == 1) {
            //只有一种方案
            System.out.println(n);
            return;
        }
        for (int i = 0; i <= colors[0]; i++) {
            //初始化,第一种球的取法
            reslut.add(Arrays.asList(i));
        }
        List<Integer> temp;

        for (int i = 1; i < k; i++) {
            //取哪种球
            List<List<Integer>> lastTurn = reslut;
            List<List<Integer>> nowTurn = new ArrayList<>();
            for (int j = 0; j < lastTurn.size(); j++) {
                //取第i种球之前有几种方案
                for (int z = 0; z <= colors[i]; z++) {
                    //第i种球可以取多少个
                    temp = new ArrayList<>();
                    //取第i-1种球的第j种方案
                    temp.addAll(lastTurn.get(j));
                    //第i种球取z个
                    temp.add(z);
                    if (i == k-1) {
                        //取完K种球并且球的总数为N(k-1是因为第一种球初始化处理了)
                        if (temp.stream().reduce(0, (u1, u2)->u1 + u2) == n) {
                            //输出方案
                            print(temp, k);
                        }
                    } else {
                        if (temp.stream().reduce(0, (u1, u2)->u1 + u2) <= n) {
                            //取完第i种球之后的取球方案
                            nowTurn.add(temp);
                        }
                    }
                }
            }
            reslut = nowTurn;
        }
    }

    public static void print(List<Integer> l, int k) {
        StringBuilder sb = new StringBuilder();
        l.forEach(u -> sb.append(u));
        for (int i = l.size(); i < k; i++) {
            sb.append(0);
        }
        resStr.add(sb.toString());
    }

3.2.1、执行结果

image.png

好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊