【数学思路】
若是八位数,每位都可以是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