【Java与数学】4个0和4个1排成一列,列出所有能组成的物理信号

【数学思路】

若是八位数,每位都可以是0或1,那么总的信号个数是2的8次方=256种,

题设里固定死必须是4个1和4个0,故信号数<256,

这种可重复元素的全排列问题有固定解法,即A_n_n/A_m_m/A_k_k,n为全体个数,m为分类个数,

具体到本题,总数为A_8_8/A_4_4/A_4_4=8*7*6*5*4*3*2*1/(4*3*2)/(4*3*2)=2*7*5=70种。

【程序思路】

将数组0,1,2,3,4,5,6,7全排列,然后按奇数为1偶数为0加到一个字符串里去,用一个TreeSet去除重复项并排序。

【代码】

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

 

主类PhisicalSignal:

import java.util.List;
import java.util.Set;
import java.util.TreeSet;

/**
 * 4个0和4个1排成一列,列出所有能组成的物理信号
 * @author 逆火
 *
 */
public class PhisicalSignal {
    public static void main(String[] args) {
        int[] numbers = {0, 1, 2, 3, 4, 5, 6, 7};
        Arranger arranger = new Arranger(numbers);
        
        Set<String> set=new TreeSet<String>();
        for (List<Integer> line : arranger.getResults()) {
            String sentence="";
            
            for(int i:line) {
                sentence+=(i%2==0)?"0":"1";
            }
            
            set.add(sentence);
        }
        
        int idx = 0;
        for(String s:set) {
            System.out.println(String.format("%02d.", ++idx)+s);
        }
    }
}

 

【输出】

01.00001111
02.00010111
03.00011011
04.00011101
05.00011110
06.00100111
07.00101011
08.00101101
09.00101110
10.00110011
11.00110101
12.00110110
13.00111001
14.00111010
15.00111100
16.01000111
17.01001011
18.01001101
19.01001110
20.01010011
21.01010101
22.01010110
23.01011001
24.01011010
25.01011100
26.01100011
27.01100101
28.01100110
29.01101001
30.01101010
31.01101100
32.01110001
33.01110010
34.01110100
35.01111000
36.10000111
37.10001011
38.10001101
39.10001110
40.10010011
41.10010101
42.10010110
43.10011001
44.10011010
45.10011100
46.10100011
47.10100101
48.10100110
49.10101001
50.10101010
51.10101100
52.10110001
53.10110010
54.10110100
55.10111000
56.11000011
57.11000101
58.11000110
59.11001001
60.11001010
61.11001100
62.11010001
63.11010010
64.11010100
65.11011000
66.11100001
67.11100010
68.11100100
69.11101000
70.11110000

 

【结论】

数学和程序可相互印证正确性。

END

posted @ 2017-09-04 21:51  逆火狂飙  阅读(205)  评论(0编辑  收藏  举报
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东