【Java与数学】从甲乙丙丁戊5人中选3人排一列,则甲不在排头的排法总数是?

【数学思路一】

一类是未选甲而进行排列的,C43*A33=24;

一类是选甲再选二进行全排列的,C42*A33=36种,其中甲不在排头的情况占整体的2/3,所以这种排法是36*2/3=24;

最后总数=24+24=48种。

【数学思路二】

上限是五选三进行排列的,C53*A33=60;

甲打头再选2进行全排列的:C42*A22=6*2=12种;

最后总数=60-12=48种

【程序思路】

为了能相互验证,程序思路和数学思路需拉开,具体进行五选三的排列再排除甲在头的方案即可。

辅助类Combination:

复制代码
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 数学中排列组合中的组合器实现
 * 传入一个数组及选择的个数,传出所有选择方案
 */
class Combination {
    /**
     * 用于存放中间结果
     */
    private Stack<Integer> stack;
    
    /**
     * 用于存放结果
     */
    private List<List<Integer>> results;
    
    /**
     * 构造函数
     * @param arr 进行组合的元素
     * @param count 选多少个
     */
    public Combination(int[] arr,int count) {
        if(count>arr.length) {
            throw new ArrayIndexOutOfBoundsException(count+">"+arr.length);
        }
        
        stack = new Stack<>();
        results=new ArrayList<>();
        doSelect(arr,count,0,0);
    }
    
    /**
     * 进行选择
     * @param arr 目标数组
     * @param expect 期望选择数量
     * @param actual 实际选择数量
     * @param current 当前下标
     */
    private void doSelect(int[] arr, int expect, int actual, int current) {
        if(actual == expect) {
            List<Integer> list=new ArrayList<>();
            
            for(int i:stack) {
                list.add(i);
            }
            
            results.add(list);
            
            return;
        }
         
        for(int i=current;i<arr.length;i++) {
            if(!stack.contains(arr[i])) {
                stack.add(arr[i]);
                doSelect(arr, expect, actual+1, i);
                stack.pop();
            }
        }
    }
    
    /**
     * 取得组合结果
     * @return
     */
    public List<List<Integer>> getResults(){
        return results;
    }
    
    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        final int[] arr= {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30};
        final int count=2;
        
        Combination c=new Combination(arr,count);
        List<List<Integer>> results=c.getResults();
        
        int idx=0;
        for(List<Integer> res:results) {
            System.out.println(String.format("%02d", ++idx) +"."+res);
        }
    }
}
复制代码

辅助类Arranger:

复制代码
import java.util.ArrayList;
import java.util.List;

/**
 * 用于产生排列结果的工具类
 * 从n个元素中取出m个元素,按照一定的顺序排成一列。得到所有排列的方案
 */
class Arranger {
    // 保存在内部的对原始元素数组的引用
    private int[] arr;

    // 总计多少元素,此即数组长度
    private final int n;

    // 选多少个
    private final int m;

    // 返回结果
    private List<List<Integer>> results;

    /**
     * 构造函数一
     * 这个构造函数是用于全排列的(n=m=数组长度)
     *
     * @arr 原始元素数组
     */
    public Arranger(int[] arr) {
        this.arr = arr;
        this.n = arr.length;
        this.m = arr.length;

        this.results = new ArrayList<>();
        doArrange(new ArrayList<>());
    }

    /**
     * 构造函数二
     * 这个构造函数是用于部分排列的(m<n=数组长度)
     *
     * @param arr    原始元素数组
     * @param selCnt 选多少个
     */
    public Arranger(int[] arr, int selCnt) {
        this.arr = arr;
        this.n = arr.length;
        this.m = selCnt;
        if (m > n) {
            throw new ArrayIndexOutOfBoundsException("m:" + m + " >n:" + n);
        }

        this.results = new ArrayList<>();
        doArrange(new ArrayList<>());
    }

    /**
     * 使用递归进行全排列,结果放在results中
     *
     * @param initialList 初始链表
     */
    private void doArrange(List<Integer> initialList) {
        List<Integer> innerList = new ArrayList<>(initialList);

        if (m == initialList.size()) {
            results.add(innerList);
        }

        for (int i = 0; i < arr.length; i++) {
            if (innerList.contains(arr[i])) {
                continue;
            }

            innerList.add(arr[i]);
            doArrange(innerList);
            innerList.remove(innerList.size() - 1);
        }
    }

    /**
     * 获得结果链表的引用
     *
     * @return
     */
    public List<List<Integer>> getResults() {
        return results;
    }

    // 测试
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4};
        Arranger arranger = new Arranger(numbers);

        System.out.println("四元素全排列示例:");
        int idx = 0;
        for (List<Integer> re : arranger.getResults()) {
            System.out.println(String.format("%02d", ++idx) + "." + re);
        }

        /*Arranger arranger2 = new Arranger(numbers, 2);
        System.out.println("\n四选二排列示例:");
        idx = 0;
        for (List<Integer> re : arranger2.getResults()) {
            System.out.println(String.format("%02d", ++idx) + "." + re);
        }*/
    }
}
复制代码

主类:

复制代码
import java.util.List;


/**
 * 从甲乙丙丁戊5人中选3人排一列,则甲不在排头的排法总数是?
 * @author ufo
 *
 */
public class OneIsntHead {
    public static void main(String[] args) {
        // 甲乙丙丁戊五人的名字
        final String[] names= {"甲","乙","丙","丁","戊",};
        
        // 甲乙丙丁戊五人的下标
        final int[] arr= {0,1,2,3,4};
        
        // 五选三的方案
        Combination cbnt=new Combination(arr,3);
        
        int idx=0;
        List<List<Integer>> results1=cbnt.getResults();
        for(List<Integer> result1:results1) {
            // 得到五选三后的数组
            int[] tmp=new int[result1.size()];
            for(int i=0;i<result1.size();i++) {
                tmp[i]=result1.get(i);
            }
            
            // 将三人进行全排列
            Arranger arranger = new Arranger(tmp);
            for (List<Integer> re : arranger.getResults()) {
                int head=re.get(0);
                if(head!=0) {// 去掉甲在排头的方案
                    String sentence=String.format("%02d.", ++idx);
                    sentence+=names[re.get(0)]+",";
                    sentence+=names[re.get(1)]+",";
                    sentence+=names[re.get(2)];
                    System.out.println(sentence);
                }
            }
        }
    }
}
复制代码

【输出】

复制代码
01.乙,甲,丙
02.乙,丙,甲
03.丙,甲,乙
04.丙,乙,甲
05.乙,甲,丁
06.乙,丁,甲
07.丁,甲,乙
08.丁,乙,甲
09.乙,甲,戊
10.乙,戊,甲
11.戊,甲,乙
12.戊,乙,甲
13.丙,甲,丁
14.丙,丁,甲
15.丁,甲,丙
16.丁,丙,甲
17.丙,甲,戊
18.丙,戊,甲
19.戊,甲,丙
20.戊,丙,甲
21.丁,甲,戊
22.丁,戊,甲
23.戊,甲,丁
24.戊,丁,甲
25.乙,丙,丁
26.乙,丁,丙
27.丙,乙,丁
28.丙,丁,乙
29.丁,乙,丙
30.丁,丙,乙
31.乙,丙,戊
32.乙,戊,丙
33.丙,乙,戊
34.丙,戊,乙
35.戊,乙,丙
36.戊,丙,乙
37.乙,丁,戊
38.乙,戊,丁
39.丁,乙,戊
40.丁,戊,乙
41.戊,乙,丁
42.戊,丁,乙
43.丙,丁,戊
44.丙,戊,丁
45.丁,丙,戊
46.丁,戊,丙
47.戊,丙,丁
48.戊,丁,丙
复制代码

 

END

 

posted @   逆火狂飙  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2020-05-24 递归向下解析算术表达式(四)
2020-05-24 递归向下解析算术表达式(三)
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东
点击右上角即可分享
微信分享提示