【数学思路一】
一类是未选甲而进行排列的,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.戊,丁,丙