【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 @ 2022-05-24 00:13  逆火狂飙  阅读(63)  评论(0编辑  收藏  举报
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东