记录 Matlab 经典、有趣的程序例子。
三位数
将 \(1\sim 9\) 这 \(9\) 个数字组成 \(3\) 个三位数,要求第 \(2\) 个三位数是第 \(1\) 个三位数的 \(2\) 倍,要求第 \(3\) 个三位数是第 \(1\) 个三位数的 \(3\) 倍,找出所有可行方案。
笔者的思路很简单,首先初始化一个 \(1 \times 10\) 数组代表数码 \(0 \sim 9\) 出现的次数,把试验的数组拼接成字符,再一个萝卜一个萝卜地填坑,如果坑 \(1\) 至坑 \(9\) 全部被填满则符合题意;比如 \(123123123\) 填坑的结果就是 \([0\ 1\ 1\ 1\ 0\ 0\ 0\ 0\ 0\ 0]\),“坑”没有被填满,不符题意。
1 | count = 0; |
当然《MATLAB 数值计算实战》作者的代码更加赏心悦目:
1 | count = 0; |
首先其转化为字符的过程中使用了列向量而行向量,于是 s
为 \(3 \times 3\) 的数组,而笔者则需要把重心放在字符串的处理上,相当伤脑筋。后面直接将 s
拉直、转置为 \(1 \times 9\) 的字符数组进行排序,与 \(1:9\) 进行对比即可,一气呵成。
杨辉三角
对于给定行数,美观输出杨辉三角,需要事先确定好每个数字所占宽度,这里将宽度设定为所有数字中最大数的字符个数的两倍(\(2d\))。其次需要控制好三角形左边的空格长度。
1 | function pasc_triangle(N) |
约瑟夫环
设有 \(n\) 个人围成一圈,从位置 \(s\ (1 \leqslant s \leqslant n)\) 上的人从 \(1\) 开始报数,数到 \(m\) 的人即出列。下一个人即原来第 \(m+1\) 位置上的人又从 \(1\) 报数,报到第 \(m\) 个人出列。重复此过程直至所有人全部出列位置。
首先需要理解一个简单的公式。
于是以下两种方法均可实现算法。
1 | function seq = joseph1(n, s, m) |
第一种方法思路很简单:总体不变,因为每轮会有人出局,所以设置“落座”记号,有人为 \(1\) 无人为 \(0\)。每轮需要有 \(m\) 次“有效的”移动,即移动到下一个座位上必须有人,否则继续移动。
第二种代码就比较简洁了,程序中的 \(s\) 时始终表示下一轮第一个人前面的位置,所以公式 \(\eqref{J}\) 需要减去 \(1\)。每轮结束移除已出列的数字,直至数组为空为止。
连续数字出现次数
对于一个行向量 \([0\ 0\ 0\ 1\ 1\ 1\ 0\ 1\ 1\ 0\ 0\ 1\ 1\ 1\ 0\ 0\ 0\ 1]\),统计连续 \(1\) 出现的位置以及次数。
考虑其一阶差分:\([0\ 0\ 1\ 0\ 0\ -1\ 1\ 0\ -1\ 0\ 1\ 0\ 0\ -1\ 0\ 0\ 1]\),可观察到原向量中开始出现 \(1\) 的位置在差分后的向量中也为 \(1\),并结束于 \(-1\) 之前。但考虑到首末问题,应该在原向量首尾各添加 \(0\) 以保证正确性。代码如下:
1 | x = [0 0 0 1 1 1 0 1 1 0 0 1 1 1 0 0 0 1]; |