【高中数学/排列组合】甲、乙、丙、丁、戊共五名同学进行劳动技术比赛,决出第一名到第五名的名次......分析5人的名次排列方式共有多少种?

【原题】

甲、乙、丙、丁、戊共五名同学进行劳动技术比赛,决出第一名到第五名的名次。

甲和乙去询问成绩,回答者对甲说:“很遗憾,你和乙都没有获得冠军”,又对乙说:“你当然不会是最差的。”

请你从这两个回答分析,5人的名次排列方式共有多少种?

 【解答】

1.直接法

第一名只能在丙丁戊三人中选,计有C_3_1种;

第五名只能从甲和丙丁戊种选,且丙丁戊还要去掉一位(成为第一名),计有C_3_1种;

中间的二三四名在剩下三人中全排列,计有A_3_3种;

总的排列方式是C_3_1*A_3_3*C_3_1=3*6*3=54种。

2.排除法

五人进行全排列的方案是A_5_5种,这是总数;

乙在首位,其余四人全排列有A_4_4种,这是需要排除的;

甲在首位,其余四人全排列有A_4_4种,这是需要排除的;

乙在末尾,其余四人全排列有A_4_4种,这是需要排除的;

注意上面两种情况多排除了一种,那就是甲在首位乙在末位其它三人全排列的情况,计有A_3_3种,这是多排除一次需要加回来的;

因此总的排列方式为A_5_5-3*A_4_4+A_3_3=120-3*24+6=2*24+6=54种。

以上两种方法从正反两方面得到了一致的结论,应该是对的。

但问题是排列总数有了,排列方案没出来,为此我们还需要程序的帮助。

【程序解法】

程序解法相对简单:只要把五人的全排列方案找出,然后去掉甲乙在首位或乙在末位的情况就好了,逻辑比数学方法简单多了。

代码如下:

主类:

package test240809;

import java.util.List;

/**
 * 
 * 甲、乙、丙、丁、戊共五名同学进行劳动技术比赛,决出第一名到第五名的名次。甲和乙去询问成绩,回答者对甲说:“很遗憾,你和乙都没有获得冠军”,又对乙说:“你当然不会是最差的。”
请你从这两个回答分析,5人的名次排列方式共有多少种?
 *
 */
public class Test1 {
    public static void main(String[] args) {
        final String[] names= {"甲","乙","丙","丁","戊"};
        final int[] arr1= {0,1,2,3,4};
        
        Arranger arranger = new Arranger(arr1,arr1.length);
        
        int idx=0;
        for (List<Integer> line : arranger.getResults()) {
            int first=line.get(0);
            int last =line.get(4);
            
            if(first==0 || first==1 || last==1) {
                continue;
            }else {
                idx++;
                
                StringBuilder sb=new StringBuilder();
                sb.append(idx+".");
                sb.append(names[line.get(0)]);
                sb.append(names[line.get(1)]);
                sb.append(names[line.get(2)]);
                sb.append(names[line.get(3)]);
                sb.append(names[line.get(4)]);
                
                System.out.println(sb.toString());
            }
        }
    }
}

辅助类Arranger:

package test240809;

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);
        }*/
    }
}

【程序输出的结果】

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.丁丙乙甲戊
31.丁丙乙戊甲
32.丁丙戊乙甲
33.丁戊甲乙丙
34.丁戊乙甲丙
35.丁戊乙丙甲
36.丁戊丙乙甲
37.戊甲乙丙丁
38.戊甲乙丁丙
39.戊甲丙乙丁
40.戊甲丁乙丙
41.戊乙甲丙丁
42.戊乙甲丁丙
43.戊乙丙甲丁
44.戊乙丙丁甲
45.戊乙丁甲丙
46.戊乙丁丙甲
47.戊丙甲乙丁
48.戊丙乙甲丁
49.戊丙乙丁甲
50.戊丙丁乙甲
51.戊丁甲乙丙
52.戊丁乙甲丙
53.戊丁乙丙甲
54.戊丁丙乙甲

复制代码

【结论】

程序结果和两种数学结果都是54种,三者可以相互印证。

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值